clang  7.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 S is matched in content.
233  // When true, P marks begin-position of the match, and calling Advance sets C
234  // to end-position of the match.
235  // If S is the empty string, then search for any letter instead (makes sense
236  // with FinishDirectiveToken=true).
237  // If EnsureStartOfWord, then skip matches that don't start a new word.
238  // If FinishDirectiveToken, then assume the match is the start of a comment
239  // directive for -verify, and extend the match to include the entire first
240  // token of that directive.
241  bool Search(StringRef S, bool EnsureStartOfWord = false,
242  bool FinishDirectiveToken = false) {
243  do {
244  if (!S.empty()) {
245  P = std::search(C, End, S.begin(), S.end());
246  PEnd = P + S.size();
247  }
248  else {
249  P = C;
250  while (P != End && !isLetter(*P))
251  ++P;
252  PEnd = P + 1;
253  }
254  if (P == End)
255  break;
256  // If not start of word but required, skip and search again.
257  if (EnsureStartOfWord
258  // Check if string literal starts a new word.
259  && !(P == Begin || isWhitespace(P[-1])
260  // Or it could be preceded by the start of a comment.
261  || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
262  && P[-2] == '/')))
263  continue;
264  if (FinishDirectiveToken) {
265  while (PEnd != End && (isAlphanumeric(*PEnd)
266  || *PEnd == '-' || *PEnd == '_'))
267  ++PEnd;
268  // Put back trailing digits and hyphens to be parsed later as a count
269  // or count range. Because -verify prefixes must start with letters,
270  // we know the actual directive we found starts with a letter, so
271  // we won't put back the entire directive word and thus record an empty
272  // string.
273  assert(isLetter(*P) && "-verify prefix must start with a letter");
274  while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
275  --PEnd;
276  }
277  return true;
278  } while (Advance());
279  return false;
280  }
281 
282  // Return true if a CloseBrace that closes the OpenBrace at the current nest
283  // level is found. When true, P marks begin-position of CloseBrace.
284  bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
285  unsigned Depth = 1;
286  P = C;
287  while (P < End) {
288  StringRef S(P, End - P);
289  if (S.startswith(OpenBrace)) {
290  ++Depth;
291  P += OpenBrace.size();
292  } else if (S.startswith(CloseBrace)) {
293  --Depth;
294  if (Depth == 0) {
295  PEnd = P + CloseBrace.size();
296  return true;
297  }
298  P += CloseBrace.size();
299  } else {
300  ++P;
301  }
302  }
303  return false;
304  }
305 
306  // Advance 1-past previous next/search.
307  // Behavior is undefined if previous next/search failed.
308  bool Advance() {
309  C = PEnd;
310  return C < End;
311  }
312 
313  // Skip zero or more whitespace.
314  void SkipWhitespace() {
315  for (; C < End && isWhitespace(*C); ++C)
316  ;
317  }
318 
319  // Return true if EOF reached.
320  bool Done() {
321  return !(C < End);
322  }
323 
324  const char * const Begin; // beginning of expected content
325  const char * const End; // end of expected content (1-past)
326  const char *C; // position of next char in content
327  const char *P;
328 
329 private:
330  const char *PEnd; // previous next/search subject end (1-past)
331 };
332 
333 } // namespace anonymous
334 
335 /// ParseDirective - Go through the comment and see if it indicates expected
336 /// diagnostics. If so, then put them in the appropriate directive list.
337 ///
338 /// Returns true if any valid directives were found.
339 static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
340  Preprocessor *PP, SourceLocation Pos,
342  DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
343 
344  // A single comment may contain multiple directives.
345  bool FoundDirective = false;
346  for (ParseHelper PH(S); !PH.Done();) {
347  // Search for the initial directive token.
348  // If one prefix, save time by searching only for its directives.
349  // Otherwise, search for any potential directive token and check it later.
350  const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
351  if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
352  : PH.Search("", true, true)))
353  break;
354  PH.Advance();
355 
356  // Default directive kind.
357  bool RegexKind = false;
358  const char* KindStr = "string";
359 
360  // Parse the initial directive token in reverse so we can easily determine
361  // its exact actual prefix. If we were to parse it from the front instead,
362  // it would be harder to determine where the prefix ends because there
363  // might be multiple matching -verify prefixes because some might prefix
364  // others.
365  StringRef DToken(PH.P, PH.C - PH.P);
366 
367  // Regex in initial directive token: -re
368  if (DToken.endswith("-re")) {
369  RegexKind = true;
370  KindStr = "regex";
371  DToken = DToken.substr(0, DToken.size()-3);
372  }
373 
374  // Type in initial directive token: -{error|warning|note|no-diagnostics}
375  DirectiveList *DL = nullptr;
376  bool NoDiag = false;
377  StringRef DType;
378  if (DToken.endswith(DType="-error"))
379  DL = ED ? &ED->Errors : nullptr;
380  else if (DToken.endswith(DType="-warning"))
381  DL = ED ? &ED->Warnings : nullptr;
382  else if (DToken.endswith(DType="-remark"))
383  DL = ED ? &ED->Remarks : nullptr;
384  else if (DToken.endswith(DType="-note"))
385  DL = ED ? &ED->Notes : nullptr;
386  else if (DToken.endswith(DType="-no-diagnostics")) {
387  NoDiag = true;
388  if (RegexKind)
389  continue;
390  }
391  else
392  continue;
393  DToken = DToken.substr(0, DToken.size()-DType.size());
394 
395  // What's left in DToken is the actual prefix. That might not be a -verify
396  // prefix even if there is only one -verify prefix (for example, the full
397  // DToken is foo-bar-warning, but foo is the only -verify prefix).
398  if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
399  continue;
400 
401  if (NoDiag) {
403  Diags.Report(Pos, diag::err_verify_invalid_no_diags)
404  << /*IsExpectedNoDiagnostics=*/true;
405  else
407  continue;
408  }
410  Diags.Report(Pos, diag::err_verify_invalid_no_diags)
411  << /*IsExpectedNoDiagnostics=*/false;
412  continue;
413  }
415 
416  // If a directive has been found but we're not interested
417  // in storing the directive information, return now.
418  if (!DL)
419  return true;
420 
421  // Next optional token: @
422  SourceLocation ExpectedLoc;
423  bool MatchAnyLine = false;
424  if (!PH.Next("@")) {
425  ExpectedLoc = Pos;
426  } else {
427  PH.Advance();
428  unsigned Line = 0;
429  bool FoundPlus = PH.Next("+");
430  if (FoundPlus || PH.Next("-")) {
431  // Relative to current line.
432  PH.Advance();
433  bool Invalid = false;
434  unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
435  if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
436  if (FoundPlus) ExpectedLine += Line;
437  else ExpectedLine -= Line;
438  ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
439  }
440  } else if (PH.Next(Line)) {
441  // Absolute line number.
442  if (Line > 0)
443  ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
444  } else if (PP && PH.Search(":")) {
445  // Specific source file.
446  StringRef Filename(PH.C, PH.P-PH.C);
447  PH.Advance();
448 
449  // Lookup file via Preprocessor, like a #include.
450  const DirectoryLookup *CurDir;
451  const FileEntry *FE =
452  PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
453  nullptr, nullptr, nullptr, nullptr);
454  if (!FE) {
455  Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
456  diag::err_verify_missing_file) << Filename << KindStr;
457  continue;
458  }
459 
460  if (SM.translateFile(FE).isInvalid())
461  SM.createFileID(FE, Pos, SrcMgr::C_User);
462 
463  if (PH.Next(Line) && Line > 0)
464  ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
465  else if (PH.Next("*")) {
466  MatchAnyLine = true;
467  ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
468  }
469  } else if (PH.Next("*")) {
470  MatchAnyLine = true;
471  ExpectedLoc = SourceLocation();
472  }
473 
474  if (ExpectedLoc.isInvalid() && !MatchAnyLine) {
475  Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
476  diag::err_verify_missing_line) << KindStr;
477  continue;
478  }
479  PH.Advance();
480  }
481 
482  // Skip optional whitespace.
483  PH.SkipWhitespace();
484 
485  // Next optional token: positive integer or a '+'.
486  unsigned Min = 1;
487  unsigned Max = 1;
488  if (PH.Next(Min)) {
489  PH.Advance();
490  // A positive integer can be followed by a '+' meaning min
491  // or more, or by a '-' meaning a range from min to max.
492  if (PH.Next("+")) {
493  Max = Directive::MaxCount;
494  PH.Advance();
495  } else if (PH.Next("-")) {
496  PH.Advance();
497  if (!PH.Next(Max) || Max < Min) {
498  Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
499  diag::err_verify_invalid_range) << KindStr;
500  continue;
501  }
502  PH.Advance();
503  } else {
504  Max = Min;
505  }
506  } else if (PH.Next("+")) {
507  // '+' on its own means "1 or more".
508  Max = Directive::MaxCount;
509  PH.Advance();
510  }
511 
512  // Skip optional whitespace.
513  PH.SkipWhitespace();
514 
515  // Next token: {{
516  if (!PH.Next("{{")) {
517  Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
518  diag::err_verify_missing_start) << KindStr;
519  continue;
520  }
521  PH.Advance();
522  const char* const ContentBegin = PH.C; // mark content begin
523 
524  // Search for token: }}
525  if (!PH.SearchClosingBrace("{{", "}}")) {
526  Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
527  diag::err_verify_missing_end) << KindStr;
528  continue;
529  }
530  const char* const ContentEnd = PH.P; // mark content end
531  PH.Advance();
532 
533  // Build directive text; convert \n to newlines.
534  std::string Text;
535  StringRef NewlineStr = "\\n";
536  StringRef Content(ContentBegin, ContentEnd-ContentBegin);
537  size_t CPos = 0;
538  size_t FPos;
539  while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
540  Text += Content.substr(CPos, FPos-CPos);
541  Text += '\n';
542  CPos = FPos + NewlineStr.size();
543  }
544  if (Text.empty())
545  Text.assign(ContentBegin, ContentEnd);
546 
547  // Check that regex directives contain at least one regex.
548  if (RegexKind && Text.find("{{") == StringRef::npos) {
549  Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
550  diag::err_verify_missing_regex) << Text;
551  return false;
552  }
553 
554  // Construct new directive.
555  std::unique_ptr<Directive> D = Directive::create(
556  RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, Min, Max);
557 
558  std::string Error;
559  if (D->isValid(Error)) {
560  DL->push_back(std::move(D));
561  FoundDirective = true;
562  } else {
563  Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
564  diag::err_verify_invalid_content)
565  << KindStr << Error;
566  }
567  }
568 
569  return FoundDirective;
570 }
571 
572 /// HandleComment - Hook into the preprocessor and extract comments containing
573 /// expected errors and warnings.
575  SourceRange Comment) {
577 
578  // If this comment is for a different source manager, ignore it.
579  if (SrcManager && &SM != SrcManager)
580  return false;
581 
582  SourceLocation CommentBegin = Comment.getBegin();
583 
584  const char *CommentRaw = SM.getCharacterData(CommentBegin);
585  StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
586 
587  if (C.empty())
588  return false;
589 
590  // Fold any "<EOL>" sequences
591  size_t loc = C.find('\\');
592  if (loc == StringRef::npos) {
593  ParseDirective(C, &ED, SM, &PP, CommentBegin, Status);
594  return false;
595  }
596 
597  std::string C2;
598  C2.reserve(C.size());
599 
600  for (size_t last = 0;; loc = C.find('\\', last)) {
601  if (loc == StringRef::npos || loc == C.size()) {
602  C2 += C.substr(last);
603  break;
604  }
605  C2 += C.substr(last, loc-last);
606  last = loc + 1;
607 
608  if (C[last] == '\n' || C[last] == '\r') {
609  ++last;
610 
611  // Escape \r\n or \n\r, but not \n\n.
612  if (last < C.size())
613  if (C[last] == '\n' || C[last] == '\r')
614  if (C[last] != C[last-1])
615  ++last;
616  } else {
617  // This was just a normal backslash.
618  C2 += '\\';
619  }
620  }
621 
622  if (!C2.empty())
623  ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status);
624  return false;
625 }
626 
627 #ifndef NDEBUG
628 /// \brief Lex the specified source file to determine whether it contains
629 /// any expected-* directives. As a Lexer is used rather than a full-blown
630 /// Preprocessor, directives inside skipped #if blocks will still be found.
631 ///
632 /// \return true if any directives were found.
634  const LangOptions &LangOpts) {
635  // Create a raw lexer to pull all the comments out of FID.
636  if (FID.isInvalid())
637  return false;
638 
639  // Create a lexer to lex all the tokens of the main file in raw mode.
640  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
641  Lexer RawLex(FID, FromFile, SM, LangOpts);
642 
643  // Return comments as tokens, this is how we find expected diagnostics.
644  RawLex.SetCommentRetentionState(true);
645 
646  Token Tok;
647  Tok.setKind(tok::comment);
650  while (Tok.isNot(tok::eof)) {
651  RawLex.LexFromRawLexer(Tok);
652  if (!Tok.is(tok::comment)) continue;
653 
654  std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
655  if (Comment.empty()) continue;
656 
657  // Find first directive.
658  if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
659  Status))
660  return true;
661  }
662  return false;
663 }
664 #endif // !NDEBUG
665 
666 /// \brief Takes a list of diagnostics that have been generated but not matched
667 /// by an expected-* directive and produces a diagnostic to the user from this.
668 static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
669  const_diag_iterator diag_begin,
670  const_diag_iterator diag_end,
671  const char *Kind) {
672  if (diag_begin == diag_end) return 0;
673 
674  SmallString<256> Fmt;
675  llvm::raw_svector_ostream OS(Fmt);
676  for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
677  if (I->first.isInvalid() || !SourceMgr)
678  OS << "\n (frontend)";
679  else {
680  OS << "\n ";
681  if (const FileEntry *File = SourceMgr->getFileEntryForID(
682  SourceMgr->getFileID(I->first)))
683  OS << " File " << File->getName();
684  OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
685  }
686  OS << ": " << I->second;
687  }
688 
689  Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
690  << Kind << /*Unexpected=*/true << OS.str();
691  return std::distance(diag_begin, diag_end);
692 }
693 
694 /// \brief Takes a list of diagnostics that were expected to have been generated
695 /// but were not and produces a diagnostic to the user from this.
696 static unsigned PrintExpected(DiagnosticsEngine &Diags,
697  SourceManager &SourceMgr,
698  std::vector<Directive *> &DL, const char *Kind) {
699  if (DL.empty())
700  return 0;
701 
702  SmallString<256> Fmt;
703  llvm::raw_svector_ostream OS(Fmt);
704  for (auto *DirPtr : DL) {
705  Directive &D = *DirPtr;
706  if (D.DiagnosticLoc.isInvalid())
707  OS << "\n File *";
708  else
709  OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc);
710  if (D.MatchAnyLine)
711  OS << " Line *";
712  else
713  OS << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
714  if (D.DirectiveLoc != D.DiagnosticLoc)
715  OS << " (directive at "
716  << SourceMgr.getFilename(D.DirectiveLoc) << ':'
717  << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')';
718  OS << ": " << D.Text;
719  }
720 
721  Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
722  << Kind << /*Unexpected=*/false << OS.str();
723  return DL.size();
724 }
725 
726 /// \brief Determine whether two source locations come from the same file.
727 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
728  SourceLocation DiagnosticLoc) {
729  while (DiagnosticLoc.isMacroID())
730  DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
731 
732  if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
733  return true;
734 
735  const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
736  if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
737  return true;
738 
739  return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
740 }
741 
742 /// CheckLists - Compare expected to seen diagnostic lists and return the
743 /// the difference between them.
744 ///
745 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
746  const char *Label,
747  DirectiveList &Left,
748  const_diag_iterator d2_begin,
749  const_diag_iterator d2_end,
750  bool IgnoreUnexpected) {
751  std::vector<Directive *> LeftOnly;
752  DiagList Right(d2_begin, d2_end);
753 
754  for (auto &Owner : Left) {
755  Directive &D = *Owner;
756  unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
757 
758  for (unsigned i = 0; i < D.Max; ++i) {
759  DiagList::iterator II, IE;
760  for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
761  if (!D.MatchAnyLine) {
762  unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
763  if (LineNo1 != LineNo2)
764  continue;
765  }
766 
767  if (!D.DiagnosticLoc.isInvalid() &&
768  !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
769  continue;
770 
771  const std::string &RightText = II->second;
772  if (D.match(RightText))
773  break;
774  }
775  if (II == IE) {
776  // Not found.
777  if (i >= D.Min) break;
778  LeftOnly.push_back(&D);
779  } else {
780  // Found. The same cannot be found twice.
781  Right.erase(II);
782  }
783  }
784  }
785  // Now all that's left in Right are those that were not matched.
786  unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
787  if (!IgnoreUnexpected)
788  num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
789  return num;
790 }
791 
792 /// CheckResults - This compares the expected results to those that
793 /// were actually reported. It emits any discrepencies. Return "true" if there
794 /// were problems. Return "false" otherwise.
795 ///
796 static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
797  const TextDiagnosticBuffer &Buffer,
798  ExpectedData &ED) {
799  // We want to capture the delta between what was expected and what was
800  // seen.
801  //
802  // Expected \ Seen - set expected but not seen
803  // Seen \ Expected - set seen but not expected
804  unsigned NumProblems = 0;
805 
806  const DiagnosticLevelMask DiagMask =
807  Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
808 
809  // See if there are error mismatches.
810  NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
811  Buffer.err_begin(), Buffer.err_end(),
812  bool(DiagnosticLevelMask::Error & DiagMask));
813 
814  // See if there are warning mismatches.
815  NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
816  Buffer.warn_begin(), Buffer.warn_end(),
817  bool(DiagnosticLevelMask::Warning & DiagMask));
818 
819  // See if there are remark mismatches.
820  NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
821  Buffer.remark_begin(), Buffer.remark_end(),
822  bool(DiagnosticLevelMask::Remark & DiagMask));
823 
824  // See if there are note mismatches.
825  NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
826  Buffer.note_begin(), Buffer.note_end(),
827  bool(DiagnosticLevelMask::Note & DiagMask));
828 
829  return NumProblems;
830 }
831 
833  FileID FID,
834  ParsedStatus PS) {
835  // Check SourceManager hasn't changed.
836  setSourceManager(SM);
837 
838 #ifndef NDEBUG
839  if (FID.isInvalid())
840  return;
841 
842  const FileEntry *FE = SM.getFileEntryForID(FID);
843 
844  if (PS == IsParsed) {
845  // Move the FileID from the unparsed set to the parsed set.
846  UnparsedFiles.erase(FID);
847  ParsedFiles.insert(std::make_pair(FID, FE));
848  } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
849  // Add the FileID to the unparsed set if we haven't seen it before.
850 
851  // Check for directives.
852  bool FoundDirectives;
853  if (PS == IsUnparsedNoDirectives)
854  FoundDirectives = false;
855  else
856  FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
857 
858  // Add the FileID to the unparsed set.
859  UnparsedFiles.insert(std::make_pair(FID,
860  UnparsedFileStatus(FE, FoundDirectives)));
861  }
862 #endif
863 }
864 
865 void VerifyDiagnosticConsumer::CheckDiagnostics() {
866  // Ensure any diagnostics go to the primary client.
867  DiagnosticConsumer *CurClient = Diags.getClient();
868  std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
869  Diags.setClient(PrimaryClient, false);
870 
871 #ifndef NDEBUG
872  // In a debug build, scan through any files that may have been missed
873  // during parsing and issue a fatal error if directives are contained
874  // within these files. If a fatal error occurs, this suggests that
875  // this file is being parsed separately from the main file, in which
876  // case consider moving the directives to the correct place, if this
877  // is applicable.
878  if (UnparsedFiles.size() > 0) {
879  // Generate a cache of parsed FileEntry pointers for alias lookups.
880  llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
881  for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
882  End = ParsedFiles.end(); I != End; ++I) {
883  if (const FileEntry *FE = I->second)
884  ParsedFileCache.insert(FE);
885  }
886 
887  // Iterate through list of unparsed files.
888  for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
889  End = UnparsedFiles.end(); I != End; ++I) {
890  const UnparsedFileStatus &Status = I->second;
891  const FileEntry *FE = Status.getFile();
892 
893  // Skip files that have been parsed via an alias.
894  if (FE && ParsedFileCache.count(FE))
895  continue;
896 
897  // Report a fatal error if this file contained directives.
898  if (Status.foundDirectives()) {
899  llvm::report_fatal_error(Twine("-verify directives found after rather"
900  " than during normal parsing of ",
901  StringRef(FE ? FE->getName() : "(unknown)")));
902  }
903  }
904 
905  // UnparsedFiles has been processed now, so clear it.
906  UnparsedFiles.clear();
907  }
908 #endif // !NDEBUG
909 
910  if (SrcManager) {
911  // Produce an error if no expected-* directives could be found in the
912  // source file(s) processed.
913  if (Status == HasNoDirectives) {
914  Diags.Report(diag::err_verify_no_directives).setForceEmit();
915  ++NumErrors;
916  Status = HasNoDirectivesReported;
917  }
918 
919  // Check that the expected diagnostics occurred.
920  NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
921  } else {
922  const DiagnosticLevelMask DiagMask =
923  ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
924  if (bool(DiagnosticLevelMask::Error & DiagMask))
925  NumErrors += PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
926  Buffer->err_end(), "error");
927  if (bool(DiagnosticLevelMask::Warning & DiagMask))
928  NumErrors += PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
929  Buffer->warn_end(), "warn");
930  if (bool(DiagnosticLevelMask::Remark & DiagMask))
931  NumErrors += PrintUnexpected(Diags, nullptr, Buffer->remark_begin(),
932  Buffer->remark_end(), "remark");
933  if (bool(DiagnosticLevelMask::Note & DiagMask))
934  NumErrors += PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
935  Buffer->note_end(), "note");
936  }
937 
938  Diags.setClient(CurClient, Owner.release() != nullptr);
939 
940  // Reset the buffer, we have processed all the diagnostics in it.
941  Buffer.reset(new TextDiagnosticBuffer());
942  ED.Reset();
943 }
944 
945 std::unique_ptr<Directive> Directive::create(bool RegexKind,
946  SourceLocation DirectiveLoc,
947  SourceLocation DiagnosticLoc,
948  bool MatchAnyLine, StringRef Text,
949  unsigned Min, unsigned Max) {
950  if (!RegexKind)
951  return llvm::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
952  MatchAnyLine, Text, Min, Max);
953 
954  // Parse the directive into a regular expression.
955  std::string RegexStr;
956  StringRef S = Text;
957  while (!S.empty()) {
958  if (S.startswith("{{")) {
959  S = S.drop_front(2);
960  size_t RegexMatchLength = S.find("}}");
961  assert(RegexMatchLength != StringRef::npos);
962  // Append the regex, enclosed in parentheses.
963  RegexStr += "(";
964  RegexStr.append(S.data(), RegexMatchLength);
965  RegexStr += ")";
966  S = S.drop_front(RegexMatchLength + 2);
967  } else {
968  size_t VerbatimMatchLength = S.find("{{");
969  if (VerbatimMatchLength == StringRef::npos)
970  VerbatimMatchLength = S.size();
971  // Escape and append the fixed string.
972  RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
973  S = S.drop_front(VerbatimMatchLength);
974  }
975  }
976 
977  return llvm::make_unique<RegexDirective>(
978  DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr);
979 }
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()))
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:521
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:1490
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:1133
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1294
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:1487
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:1327
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.
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
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:1326
const FormatToken & Tok
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
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:1522
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:1412
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.
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.
static ICEDiag NoDiag()
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:1328
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.
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.
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
Definition: Diagnostic.h:499
SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const
Get the source location in FID for the given line:col.
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.
const_iterator warn_begin() const
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:519
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:1315
DiagnosticLevelMask
A bitmask representing the diagnostic levels used by VerifyDiagnosticConsumer.
StringRef Text
Definition: Format.cpp:1523
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:513