VerifyDiagnosticConsumer.cpp revision 234353
1226586Sdim//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===//
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim//
10226586Sdim// This is a concrete diagnostic client, which buffers the diagnostic messages.
11226586Sdim//
12226586Sdim//===----------------------------------------------------------------------===//
13226586Sdim
14226586Sdim#include "clang/Frontend/VerifyDiagnosticConsumer.h"
15226586Sdim#include "clang/Frontend/FrontendDiagnostic.h"
16226586Sdim#include "clang/Frontend/TextDiagnosticBuffer.h"
17226586Sdim#include "clang/Lex/Preprocessor.h"
18226586Sdim#include "llvm/ADT/SmallString.h"
19226586Sdim#include "llvm/Support/Regex.h"
20226586Sdim#include "llvm/Support/raw_ostream.h"
21234353Sdim#include <climits>
22234353Sdim
23226586Sdimusing namespace clang;
24226586Sdim
25226586SdimVerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
26226586Sdim  : Diags(_Diags), PrimaryClient(Diags.getClient()),
27226586Sdim    OwnsPrimaryClient(Diags.ownsClient()),
28226586Sdim    Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0)
29226586Sdim{
30226586Sdim  Diags.takeClient();
31226586Sdim}
32226586Sdim
33226586SdimVerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
34226586Sdim  CheckDiagnostics();
35226586Sdim  Diags.takeClient();
36226586Sdim  if (OwnsPrimaryClient)
37226586Sdim    delete PrimaryClient;
38226586Sdim}
39226586Sdim
40226586Sdim// DiagnosticConsumer interface.
41226586Sdim
42226586Sdimvoid VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
43234353Sdim                                               const Preprocessor *PP) {
44226586Sdim  // FIXME: Const hack, we screw up the preprocessor but in practice its ok
45226586Sdim  // because it doesn't get reused. It would be better if we could make a copy
46226586Sdim  // though.
47226586Sdim  CurrentPreprocessor = const_cast<Preprocessor*>(PP);
48226586Sdim
49226586Sdim  PrimaryClient->BeginSourceFile(LangOpts, PP);
50226586Sdim}
51226586Sdim
52226586Sdimvoid VerifyDiagnosticConsumer::EndSourceFile() {
53226586Sdim  CheckDiagnostics();
54226586Sdim
55226586Sdim  PrimaryClient->EndSourceFile();
56226586Sdim
57226586Sdim  CurrentPreprocessor = 0;
58226586Sdim}
59226586Sdim
60226586Sdimvoid VerifyDiagnosticConsumer::HandleDiagnostic(
61226586Sdim      DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
62226586Sdim  if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
63226586Sdim    const SourceManager &SM = Info.getSourceManager();
64226586Sdim    FirstErrorFID = SM.getFileID(Info.getLocation());
65226586Sdim  }
66226586Sdim  // Send the diagnostic to the buffer, we will check it once we reach the end
67226586Sdim  // of the source file (or are destructed).
68226586Sdim  Buffer->HandleDiagnostic(DiagLevel, Info);
69226586Sdim}
70226586Sdim
71226586Sdim//===----------------------------------------------------------------------===//
72226586Sdim// Checking diagnostics implementation.
73226586Sdim//===----------------------------------------------------------------------===//
74226586Sdim
75226586Sdimtypedef TextDiagnosticBuffer::DiagList DiagList;
76226586Sdimtypedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
77226586Sdim
78226586Sdimnamespace {
79226586Sdim
80226586Sdim/// Directive - Abstract class representing a parsed verify directive.
81226586Sdim///
82226586Sdimclass Directive {
83226586Sdimpublic:
84226586Sdim  static Directive* Create(bool RegexKind, const SourceLocation &Location,
85226586Sdim                           const std::string &Text, unsigned Count);
86226586Sdimpublic:
87234353Sdim  /// Constant representing one or more matches aka regex "+".
88234353Sdim  static const unsigned OneOrMoreCount =  UINT_MAX;
89234353Sdim
90226586Sdim  SourceLocation Location;
91226586Sdim  const std::string Text;
92226586Sdim  unsigned Count;
93226586Sdim
94226586Sdim  virtual ~Directive() { }
95226586Sdim
96226586Sdim  // Returns true if directive text is valid.
97226586Sdim  // Otherwise returns false and populates E.
98226586Sdim  virtual bool isValid(std::string &Error) = 0;
99226586Sdim
100226586Sdim  // Returns true on match.
101226586Sdim  virtual bool Match(const std::string &S) = 0;
102226586Sdim
103226586Sdimprotected:
104226586Sdim  Directive(const SourceLocation &Location, const std::string &Text,
105226586Sdim            unsigned Count)
106226586Sdim    : Location(Location), Text(Text), Count(Count) { }
107226586Sdim
108226586Sdimprivate:
109226586Sdim  Directive(const Directive&); // DO NOT IMPLEMENT
110226586Sdim  void operator=(const Directive&); // DO NOT IMPLEMENT
111226586Sdim};
112226586Sdim
113226586Sdim/// StandardDirective - Directive with string matching.
114226586Sdim///
115226586Sdimclass StandardDirective : public Directive {
116226586Sdimpublic:
117226586Sdim  StandardDirective(const SourceLocation &Location, const std::string &Text,
118226586Sdim                    unsigned Count)
119226586Sdim    : Directive(Location, Text, Count) { }
120226586Sdim
121226586Sdim  virtual bool isValid(std::string &Error) {
122226586Sdim    // all strings are considered valid; even empty ones
123226586Sdim    return true;
124226586Sdim  }
125226586Sdim
126226586Sdim  virtual bool Match(const std::string &S) {
127234353Sdim    return S.find(Text) != std::string::npos;
128226586Sdim  }
129226586Sdim};
130226586Sdim
131226586Sdim/// RegexDirective - Directive with regular-expression matching.
132226586Sdim///
133226586Sdimclass RegexDirective : public Directive {
134226586Sdimpublic:
135226586Sdim  RegexDirective(const SourceLocation &Location, const std::string &Text,
136226586Sdim                 unsigned Count)
137226586Sdim    : Directive(Location, Text, Count), Regex(Text) { }
138226586Sdim
139226586Sdim  virtual bool isValid(std::string &Error) {
140226586Sdim    if (Regex.isValid(Error))
141226586Sdim      return true;
142226586Sdim    return false;
143226586Sdim  }
144226586Sdim
145226586Sdim  virtual bool Match(const std::string &S) {
146226586Sdim    return Regex.match(S);
147226586Sdim  }
148226586Sdim
149226586Sdimprivate:
150226586Sdim  llvm::Regex Regex;
151226586Sdim};
152226586Sdim
153226586Sdimtypedef std::vector<Directive*> DirectiveList;
154226586Sdim
155226586Sdim/// ExpectedData - owns directive objects and deletes on destructor.
156226586Sdim///
157226586Sdimstruct ExpectedData {
158226586Sdim  DirectiveList Errors;
159226586Sdim  DirectiveList Warnings;
160226586Sdim  DirectiveList Notes;
161226586Sdim
162226586Sdim  ~ExpectedData() {
163226586Sdim    DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 };
164226586Sdim    for (DirectiveList **PL = Lists; *PL; ++PL) {
165226586Sdim      DirectiveList * const L = *PL;
166226586Sdim      for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I)
167226586Sdim        delete *I;
168226586Sdim    }
169226586Sdim  }
170226586Sdim};
171226586Sdim
172226586Sdimclass ParseHelper
173226586Sdim{
174226586Sdimpublic:
175226586Sdim  ParseHelper(const char *Begin, const char *End)
176226586Sdim    : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
177226586Sdim
178226586Sdim  // Return true if string literal is next.
179226586Sdim  bool Next(StringRef S) {
180226586Sdim    P = C;
181226586Sdim    PEnd = C + S.size();
182226586Sdim    if (PEnd > End)
183226586Sdim      return false;
184226586Sdim    return !memcmp(P, S.data(), S.size());
185226586Sdim  }
186226586Sdim
187226586Sdim  // Return true if number is next.
188226586Sdim  // Output N only if number is next.
189226586Sdim  bool Next(unsigned &N) {
190226586Sdim    unsigned TMP = 0;
191226586Sdim    P = C;
192226586Sdim    for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
193226586Sdim      TMP *= 10;
194226586Sdim      TMP += P[0] - '0';
195226586Sdim    }
196226586Sdim    if (P == C)
197226586Sdim      return false;
198226586Sdim    PEnd = P;
199226586Sdim    N = TMP;
200226586Sdim    return true;
201226586Sdim  }
202226586Sdim
203226586Sdim  // Return true if string literal is found.
204226586Sdim  // When true, P marks begin-position of S in content.
205226586Sdim  bool Search(StringRef S) {
206226586Sdim    P = std::search(C, End, S.begin(), S.end());
207226586Sdim    PEnd = P + S.size();
208226586Sdim    return P != End;
209226586Sdim  }
210226586Sdim
211226586Sdim  // Advance 1-past previous next/search.
212226586Sdim  // Behavior is undefined if previous next/search failed.
213226586Sdim  bool Advance() {
214226586Sdim    C = PEnd;
215226586Sdim    return C < End;
216226586Sdim  }
217226586Sdim
218226586Sdim  // Skip zero or more whitespace.
219226586Sdim  void SkipWhitespace() {
220226586Sdim    for (; C < End && isspace(*C); ++C)
221226586Sdim      ;
222226586Sdim  }
223226586Sdim
224226586Sdim  // Return true if EOF reached.
225226586Sdim  bool Done() {
226226586Sdim    return !(C < End);
227226586Sdim  }
228226586Sdim
229226586Sdim  const char * const Begin; // beginning of expected content
230226586Sdim  const char * const End;   // end of expected content (1-past)
231226586Sdim  const char *C;            // position of next char in content
232226586Sdim  const char *P;
233226586Sdim
234226586Sdimprivate:
235226586Sdim  const char *PEnd; // previous next/search subject end (1-past)
236226586Sdim};
237226586Sdim
238226586Sdim} // namespace anonymous
239226586Sdim
240226586Sdim/// ParseDirective - Go through the comment and see if it indicates expected
241226586Sdim/// diagnostics. If so, then put them in the appropriate directive list.
242226586Sdim///
243226586Sdimstatic void ParseDirective(const char *CommentStart, unsigned CommentLen,
244226586Sdim                           ExpectedData &ED, Preprocessor &PP,
245226586Sdim                           SourceLocation Pos) {
246226586Sdim  // A single comment may contain multiple directives.
247226586Sdim  for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
248226586Sdim    // search for token: expected
249226586Sdim    if (!PH.Search("expected"))
250226586Sdim      break;
251226586Sdim    PH.Advance();
252226586Sdim
253226586Sdim    // next token: -
254226586Sdim    if (!PH.Next("-"))
255226586Sdim      continue;
256226586Sdim    PH.Advance();
257226586Sdim
258226586Sdim    // next token: { error | warning | note }
259226586Sdim    DirectiveList* DL = NULL;
260226586Sdim    if (PH.Next("error"))
261226586Sdim      DL = &ED.Errors;
262226586Sdim    else if (PH.Next("warning"))
263226586Sdim      DL = &ED.Warnings;
264226586Sdim    else if (PH.Next("note"))
265226586Sdim      DL = &ED.Notes;
266226586Sdim    else
267226586Sdim      continue;
268226586Sdim    PH.Advance();
269226586Sdim
270226586Sdim    // default directive kind
271226586Sdim    bool RegexKind = false;
272226586Sdim    const char* KindStr = "string";
273226586Sdim
274226586Sdim    // next optional token: -
275226586Sdim    if (PH.Next("-re")) {
276226586Sdim      PH.Advance();
277226586Sdim      RegexKind = true;
278226586Sdim      KindStr = "regex";
279226586Sdim    }
280226586Sdim
281226586Sdim    // skip optional whitespace
282226586Sdim    PH.SkipWhitespace();
283226586Sdim
284234353Sdim    // next optional token: positive integer or a '+'.
285226586Sdim    unsigned Count = 1;
286226586Sdim    if (PH.Next(Count))
287226586Sdim      PH.Advance();
288234353Sdim    else if (PH.Next("+")) {
289234353Sdim      Count = Directive::OneOrMoreCount;
290234353Sdim      PH.Advance();
291234353Sdim    }
292226586Sdim
293226586Sdim    // skip optional whitespace
294226586Sdim    PH.SkipWhitespace();
295226586Sdim
296226586Sdim    // next token: {{
297226586Sdim    if (!PH.Next("{{")) {
298226586Sdim      PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin),
299226586Sdim              diag::err_verify_missing_start) << KindStr;
300226586Sdim      continue;
301226586Sdim    }
302226586Sdim    PH.Advance();
303226586Sdim    const char* const ContentBegin = PH.C; // mark content begin
304226586Sdim
305226586Sdim    // search for token: }}
306226586Sdim    if (!PH.Search("}}")) {
307226586Sdim      PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin),
308226586Sdim              diag::err_verify_missing_end) << KindStr;
309226586Sdim      continue;
310226586Sdim    }
311226586Sdim    const char* const ContentEnd = PH.P; // mark content end
312226586Sdim    PH.Advance();
313226586Sdim
314226586Sdim    // build directive text; convert \n to newlines
315226586Sdim    std::string Text;
316226586Sdim    StringRef NewlineStr = "\\n";
317226586Sdim    StringRef Content(ContentBegin, ContentEnd-ContentBegin);
318226586Sdim    size_t CPos = 0;
319226586Sdim    size_t FPos;
320226586Sdim    while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
321226586Sdim      Text += Content.substr(CPos, FPos-CPos);
322226586Sdim      Text += '\n';
323226586Sdim      CPos = FPos + NewlineStr.size();
324226586Sdim    }
325226586Sdim    if (Text.empty())
326226586Sdim      Text.assign(ContentBegin, ContentEnd);
327226586Sdim
328226586Sdim    // construct new directive
329226586Sdim    Directive *D = Directive::Create(RegexKind, Pos, Text, Count);
330226586Sdim    std::string Error;
331226586Sdim    if (D->isValid(Error))
332226586Sdim      DL->push_back(D);
333226586Sdim    else {
334226586Sdim      PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin),
335226586Sdim              diag::err_verify_invalid_content)
336226586Sdim        << KindStr << Error;
337226586Sdim    }
338226586Sdim  }
339226586Sdim}
340226586Sdim
341226586Sdim/// FindExpectedDiags - Lex the main source file to find all of the
342226586Sdim//   expected errors and warnings.
343226586Sdimstatic void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
344226586Sdim  // Create a raw lexer to pull all the comments out of FID.
345226586Sdim  if (FID.isInvalid())
346226586Sdim    return;
347226586Sdim
348226586Sdim  SourceManager& SM = PP.getSourceManager();
349226586Sdim  // Create a lexer to lex all the tokens of the main file in raw mode.
350226586Sdim  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
351234353Sdim  Lexer RawLex(FID, FromFile, SM, PP.getLangOpts());
352226586Sdim
353226586Sdim  // Return comments as tokens, this is how we find expected diagnostics.
354226586Sdim  RawLex.SetCommentRetentionState(true);
355226586Sdim
356226586Sdim  Token Tok;
357226586Sdim  Tok.setKind(tok::comment);
358226586Sdim  while (Tok.isNot(tok::eof)) {
359226586Sdim    RawLex.Lex(Tok);
360226586Sdim    if (!Tok.is(tok::comment)) continue;
361226586Sdim
362226586Sdim    std::string Comment = PP.getSpelling(Tok);
363226586Sdim    if (Comment.empty()) continue;
364226586Sdim
365226586Sdim    // Find all expected errors/warnings/notes.
366226586Sdim    ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation());
367226586Sdim  };
368226586Sdim}
369226586Sdim
370226586Sdim/// PrintProblem - This takes a diagnostic map of the delta between expected and
371226586Sdim/// seen diagnostics. If there's anything in it, then something unexpected
372226586Sdim/// happened. Print the map out in a nice format and return "true". If the map
373226586Sdim/// is empty and we're not going to print things, then return "false".
374226586Sdim///
375226586Sdimstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
376226586Sdim                             const_diag_iterator diag_begin,
377226586Sdim                             const_diag_iterator diag_end,
378226586Sdim                             const char *Kind, bool Expected) {
379226586Sdim  if (diag_begin == diag_end) return 0;
380226586Sdim
381234353Sdim  SmallString<256> Fmt;
382226586Sdim  llvm::raw_svector_ostream OS(Fmt);
383226586Sdim  for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
384226586Sdim    if (I->first.isInvalid() || !SourceMgr)
385226586Sdim      OS << "\n  (frontend)";
386226586Sdim    else
387226586Sdim      OS << "\n  Line " << SourceMgr->getPresumedLineNumber(I->first);
388226586Sdim    OS << ": " << I->second;
389226586Sdim  }
390226586Sdim
391226586Sdim  Diags.Report(diag::err_verify_inconsistent_diags)
392226586Sdim    << Kind << !Expected << OS.str();
393226586Sdim  return std::distance(diag_begin, diag_end);
394226586Sdim}
395226586Sdim
396226586Sdimstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
397226586Sdim                             DirectiveList &DL, const char *Kind,
398226586Sdim                             bool Expected) {
399226586Sdim  if (DL.empty())
400226586Sdim    return 0;
401226586Sdim
402234353Sdim  SmallString<256> Fmt;
403226586Sdim  llvm::raw_svector_ostream OS(Fmt);
404226586Sdim  for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
405226586Sdim    Directive& D = **I;
406226586Sdim    if (D.Location.isInvalid() || !SourceMgr)
407226586Sdim      OS << "\n  (frontend)";
408226586Sdim    else
409226586Sdim      OS << "\n  Line " << SourceMgr->getPresumedLineNumber(D.Location);
410226586Sdim    OS << ": " << D.Text;
411226586Sdim  }
412226586Sdim
413226586Sdim  Diags.Report(diag::err_verify_inconsistent_diags)
414226586Sdim    << Kind << !Expected << OS.str();
415226586Sdim  return DL.size();
416226586Sdim}
417226586Sdim
418226586Sdim/// CheckLists - Compare expected to seen diagnostic lists and return the
419226586Sdim/// the difference between them.
420226586Sdim///
421226586Sdimstatic unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
422226586Sdim                           const char *Label,
423226586Sdim                           DirectiveList &Left,
424226586Sdim                           const_diag_iterator d2_begin,
425226586Sdim                           const_diag_iterator d2_end) {
426226586Sdim  DirectiveList LeftOnly;
427226586Sdim  DiagList Right(d2_begin, d2_end);
428226586Sdim
429226586Sdim  for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
430226586Sdim    Directive& D = **I;
431226586Sdim    unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location);
432234353Sdim    bool FoundOnce = false;
433226586Sdim
434226586Sdim    for (unsigned i = 0; i < D.Count; ++i) {
435226586Sdim      DiagList::iterator II, IE;
436226586Sdim      for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
437226586Sdim        unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
438226586Sdim        if (LineNo1 != LineNo2)
439226586Sdim          continue;
440226586Sdim
441226586Sdim        const std::string &RightText = II->second;
442226586Sdim        if (D.Match(RightText))
443226586Sdim          break;
444226586Sdim      }
445226586Sdim      if (II == IE) {
446234353Sdim        if (D.Count == D.OneOrMoreCount) {
447234353Sdim          if (!FoundOnce)
448234353Sdim            LeftOnly.push_back(*I);
449234353Sdim          // We are only interested in at least one match, so exit the loop.
450234353Sdim          break;
451234353Sdim        }
452226586Sdim        // Not found.
453226586Sdim        LeftOnly.push_back(*I);
454226586Sdim      } else {
455226586Sdim        // Found. The same cannot be found twice.
456226586Sdim        Right.erase(II);
457234353Sdim        FoundOnce = true;
458226586Sdim      }
459226586Sdim    }
460226586Sdim  }
461226586Sdim  // Now all that's left in Right are those that were not matched.
462234353Sdim  unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true);
463234353Sdim  num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
464234353Sdim                      Label, false);
465234353Sdim  return num;
466226586Sdim}
467226586Sdim
468226586Sdim/// CheckResults - This compares the expected results to those that
469226586Sdim/// were actually reported. It emits any discrepencies. Return "true" if there
470226586Sdim/// were problems. Return "false" otherwise.
471226586Sdim///
472226586Sdimstatic unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
473226586Sdim                             const TextDiagnosticBuffer &Buffer,
474226586Sdim                             ExpectedData &ED) {
475226586Sdim  // We want to capture the delta between what was expected and what was
476226586Sdim  // seen.
477226586Sdim  //
478226586Sdim  //   Expected \ Seen - set expected but not seen
479226586Sdim  //   Seen \ Expected - set seen but not expected
480226586Sdim  unsigned NumProblems = 0;
481226586Sdim
482226586Sdim  // See if there are error mismatches.
483226586Sdim  NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
484226586Sdim                            Buffer.err_begin(), Buffer.err_end());
485226586Sdim
486226586Sdim  // See if there are warning mismatches.
487226586Sdim  NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
488226586Sdim                            Buffer.warn_begin(), Buffer.warn_end());
489226586Sdim
490226586Sdim  // See if there are note mismatches.
491226586Sdim  NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
492226586Sdim                            Buffer.note_begin(), Buffer.note_end());
493226586Sdim
494226586Sdim  return NumProblems;
495226586Sdim}
496226586Sdim
497226586Sdimvoid VerifyDiagnosticConsumer::CheckDiagnostics() {
498226586Sdim  ExpectedData ED;
499226586Sdim
500226586Sdim  // Ensure any diagnostics go to the primary client.
501226586Sdim  bool OwnsCurClient = Diags.ownsClient();
502226586Sdim  DiagnosticConsumer *CurClient = Diags.takeClient();
503226586Sdim  Diags.setClient(PrimaryClient, false);
504226586Sdim
505226586Sdim  // If we have a preprocessor, scan the source for expected diagnostic
506226586Sdim  // markers. If not then any diagnostics are unexpected.
507226586Sdim  if (CurrentPreprocessor) {
508226586Sdim    SourceManager &SM = CurrentPreprocessor->getSourceManager();
509226586Sdim    // Extract expected-error strings from main file.
510226586Sdim    FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
511226586Sdim    // Only check for expectations in other diagnostic locations
512226586Sdim    // if they are not the main file (via ID or FileEntry) - the main
513226586Sdim    // file has already been looked at, and its expectations must not
514226586Sdim    // be added twice.
515226586Sdim    if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
516226586Sdim        && (!SM.getFileEntryForID(FirstErrorFID)
517226586Sdim            || (SM.getFileEntryForID(FirstErrorFID) !=
518226586Sdim                SM.getFileEntryForID(SM.getMainFileID())))) {
519226586Sdim      FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
520226586Sdim      FirstErrorFID = FileID();
521226586Sdim    }
522226586Sdim
523226586Sdim    // Check that the expected diagnostics occurred.
524226586Sdim    NumErrors += CheckResults(Diags, SM, *Buffer, ED);
525226586Sdim  } else {
526226586Sdim    NumErrors += (PrintProblem(Diags, 0,
527226586Sdim                               Buffer->err_begin(), Buffer->err_end(),
528226586Sdim                               "error", false) +
529226586Sdim                  PrintProblem(Diags, 0,
530226586Sdim                               Buffer->warn_begin(), Buffer->warn_end(),
531226586Sdim                               "warn", false) +
532226586Sdim                  PrintProblem(Diags, 0,
533226586Sdim                               Buffer->note_begin(), Buffer->note_end(),
534226586Sdim                               "note", false));
535226586Sdim  }
536226586Sdim
537226586Sdim  Diags.takeClient();
538226586Sdim  Diags.setClient(CurClient, OwnsCurClient);
539226586Sdim
540226586Sdim  // Reset the buffer, we have processed all the diagnostics in it.
541226586Sdim  Buffer.reset(new TextDiagnosticBuffer());
542226586Sdim}
543226586Sdim
544226586SdimDiagnosticConsumer *
545226586SdimVerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const {
546226586Sdim  if (!Diags.getClient())
547226586Sdim    Diags.setClient(PrimaryClient->clone(Diags));
548226586Sdim
549226586Sdim  return new VerifyDiagnosticConsumer(Diags);
550226586Sdim}
551226586Sdim
552226586SdimDirective* Directive::Create(bool RegexKind, const SourceLocation &Location,
553226586Sdim                             const std::string &Text, unsigned Count) {
554226586Sdim  if (RegexKind)
555226586Sdim    return new RegexDirective(Location, Text, Count);
556226586Sdim  return new StandardDirective(Location, Text, Count);
557226586Sdim}
558