zcov: / lib/Frontend/VerifyDiagnosticsClient.cpp


Files: 1 Branches Taken: 73.8% 59 / 80
Generated: 2010-02-10 01:31 Branches Executed: 92.5% 74 / 80
Line Coverage: 93.8% 121 / 129


Programs: 2 Runs 3018


       1                 : //===--- VerifyDiagnosticsClient.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                 : 
      14                 : #include "clang/Frontend/VerifyDiagnosticsClient.h"
      15                 : #include "clang/Frontend/FrontendDiagnostic.h"
      16                 : #include "clang/Frontend/TextDiagnosticBuffer.h"
      17                 : #include "clang/Lex/Preprocessor.h"
      18                 : #include "llvm/ADT/SmallString.h"
      19                 : #include "llvm/Support/raw_ostream.h"
      20                 : using namespace clang;
      21                 : 
      22                 : VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
      23             1312:                                                  DiagnosticClient *_Primary)
      24                 :   : Diags(_Diags), PrimaryClient(_Primary),
      25             1312:     Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) {
      26             1312: }
      27                 : 
      28             1312: VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
      29             1312:   CheckDiagnostics();
                     1312: branch 3 taken
                        0: branch 4 not taken
                        0: branch 9 not taken
                        0: branch 10 not taken
                        0: branch 15 not taken
                        0: branch 16 not taken
      30             1312: }
      31                 : 
      32                 : // DiagnosticClient interface.
      33                 : 
      34                 : void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
      35             1312:                                              const Preprocessor *PP) {
      36                 :   // FIXME: Const hack, we screw up the preprocessor but in practice its ok
      37                 :   // because it doesn't get reused. It would be better if we could make a copy
      38                 :   // though.
      39             1312:   CurrentPreprocessor = const_cast<Preprocessor*>(PP);
      40                 : 
      41             1312:   PrimaryClient->BeginSourceFile(LangOpts, PP);
      42             1312: }
      43                 : 
      44             1312: void VerifyDiagnosticsClient::EndSourceFile() {
      45             1312:   CheckDiagnostics();
      46                 : 
      47             1312:   PrimaryClient->EndSourceFile();
      48                 : 
      49             1312:   CurrentPreprocessor = 0;
      50             1312: }
      51                 : 
      52                 : void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
      53             7098:                                               const DiagnosticInfo &Info) {
      54                 :   // Send the diagnostic to the buffer, we will check it once we reach the end
      55                 :   // of the source file (or are destructed).
      56             7098:   Buffer->HandleDiagnostic(DiagLevel, Info);
      57             7098: }
      58                 : 
      59                 : // FIXME: It would be nice to just get this from the primary diagnostic client
      60                 : // or something.
      61             1312: bool VerifyDiagnosticsClient::HadErrors() {
      62             1312:   CheckDiagnostics();
      63                 : 
      64             1312:   return NumErrors != 0;
      65                 : }
      66                 : 
      67                 : //===----------------------------------------------------------------------===//
      68                 : // Checking diagnostics implementation.
      69                 : //===----------------------------------------------------------------------===//
      70                 : 
      71                 : typedef TextDiagnosticBuffer::DiagList DiagList;
      72                 : typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
      73                 : 
      74                 : /// FindDiagnostics - Go through the comment and see if it indicates expected
      75                 : /// diagnostics. If so, then put them in a diagnostic list.
      76                 : ///
      77                 : static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
      78                 :                             DiagList &ExpectedDiags,
      79                 :                             Preprocessor &PP, SourceLocation Pos,
      80            46824:                             const char *ExpectedStr) {
      81            46824:   const char *CommentEnd = CommentStart+CommentLen;
      82            46824:   unsigned ExpectedStrLen = strlen(ExpectedStr);
      83                 : 
      84                 :   // Find all expected-foo diagnostics in the string and add them to
      85                 :   // ExpectedDiags.
                   212831: branch 1 taken
                        0: branch 2 not taken
      86            53479:   while (CommentStart != CommentEnd) {
      87           212831:     CommentStart = std::find(CommentStart, CommentEnd, 'e');
                   166007: branch 0 taken
                    46824: branch 1 taken
      88           212831:     if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
      89                 : 
      90                 :     // If this isn't expected-foo, ignore it.
                   159352: branch 1 taken
                     6655: branch 2 taken
      91           166007:     if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
      92           159352:       ++CommentStart;
      93           159352:       continue;
      94                 :     }
      95                 : 
      96             6655:     CommentStart += ExpectedStrLen;
      97                 : 
      98                 :     // Skip whitespace.
                    10452: branch 0 taken
                        0: branch 1 not taken
                     3797: branch 3 taken
                     6655: branch 4 taken
      99            17107:     while (CommentStart != CommentEnd &&
     100                 :            isspace(CommentStart[0]))
     101             3797:       ++CommentStart;
     102                 : 
     103                 :     // Default, if we find the '{' now, is 1 time.
     104             6655:     int Times = 1;
     105             6655:     int Temp = 0;
     106                 :     // In extended syntax, there could be a digit now.
                     6877: branch 0 taken
                        0: branch 1 not taken
                     6733: branch 2 taken
                      144: branch 3 taken
                      222: branch 4 taken
                     6511: branch 5 taken
     107            13532:     while (CommentStart != CommentEnd &&
     108                 :            CommentStart[0] >= '0' && CommentStart[0] <= '9') {
     109              222:       Temp *= 10;
     110              222:       Temp += CommentStart[0] - '0';
     111              222:       ++CommentStart;
     112                 :     }
                      220: branch 0 taken
                     6435: branch 1 taken
     113             6655:     if (Temp > 0)
     114              220:       Times = Temp;
     115                 : 
     116                 :     // Skip whitespace again.
                     6799: branch 0 taken
                        0: branch 1 not taken
                      144: branch 3 taken
                     6655: branch 4 taken
     117            13454:     while (CommentStart != CommentEnd &&
     118                 :            isspace(CommentStart[0]))
     119              144:       ++CommentStart;
     120                 : 
     121                 :     // We should have a {{ now.
                     6655: branch 0 taken
                        0: branch 1 not taken
                     6655: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                     6655: branch 5 taken
     122             6655:     if (CommentEnd-CommentStart < 2 ||
     123                 :         CommentStart[0] != '{' || CommentStart[1] != '{') {
                        0: branch 1 not taken
                        0: branch 2 not taken
     124                0:       if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
     125                0:         PP.Diag(Pos, diag::err_verify_bogus_characters);
     126                 :       else
     127                0:         PP.Diag(Pos, diag::err_verify_missing_start);
     128                0:       return;
     129                 :     }
     130             6655:     CommentStart += 2;
     131                 : 
     132                 :     // Find the }}.
     133             6655:     const char *ExpectedEnd = CommentStart;
     134                6:     while (1) {
     135             6661:       ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
                        0: branch 0 not taken
                     6661: branch 1 taken
     136             6661:       if (CommentEnd-ExpectedEnd < 2) {
     137                0:         PP.Diag(Pos, diag::err_verify_missing_end);
     138                0:         return;
     139                 :       }
     140                 : 
                        6: branch 0 taken
                     6655: branch 1 taken
     141             6661:       if (ExpectedEnd[1] == '}')
     142             6655:         break;
     143                 : 
     144                6:       ++ExpectedEnd;  // Skip over singular }'s
     145                 :     }
     146                 : 
     147             6655:     std::string Msg(CommentStart, ExpectedEnd);
     148                 :     std::string::size_type FindPos;
                       18: branch 1 taken
                     6655: branch 2 taken
     149            13328:     while ((FindPos = Msg.find("\\n")) != std::string::npos)
     150               18:       Msg.replace(FindPos, 2, "\n");
     151                 :     // Add is possibly multiple times.
                     7095: branch 0 taken
                     6655: branch 1 taken
     152            13750:     for (int i = 0; i < Times; ++i)
     153             7095:       ExpectedDiags.push_back(std::make_pair(Pos, Msg));
     154                 : 
     155             6655:     CommentStart = ExpectedEnd;
     156                 :   }
     157                 : }
     158                 : 
     159                 : /// FindExpectedDiags - Lex the main source file to find all of the
     160                 : //   expected errors and warnings.
     161                 : static void FindExpectedDiags(Preprocessor &PP,
     162                 :                               DiagList &ExpectedErrors,
     163                 :                               DiagList &ExpectedWarnings,
     164             1312:                               DiagList &ExpectedNotes) {
     165                 :   // Create a raw lexer to pull all the comments out of the main file.  We don't
     166                 :   // want to look in #include'd headers for expected-error strings.
     167             1312:   SourceManager &SM = PP.getSourceManager();
     168             1312:   FileID FID = SM.getMainFileID();
                        0: branch 2 not taken
                     1312: branch 3 taken
     169             1312:   if (SM.getMainFileID().isInvalid())
     170                0:     return;
     171                 : 
     172                 :   // Create a lexer to lex all the tokens of the main file in raw mode.
     173             1312:   const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
     174             1312:   Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
     175                 : 
     176                 :   // Return comments as tokens, this is how we find expected diagnostics.
     177             1312:   RawLex.SetCommentRetentionState(true);
     178                 : 
     179             1312:   Token Tok;
     180             1312:   Tok.setKind(tok::comment);
                    15608: branch 1 taken
                        0: branch 2 not taken
                   340434: branch 4 taken
                     1312: branch 5 taken
     181           358666:   while (Tok.isNot(tok::eof)) {
     182           340434:     RawLex.Lex(Tok);
                    15608: branch 1 taken
                   324826: branch 2 taken
     183           340434:     if (!Tok.is(tok::comment)) continue;
     184                 : 
     185            15608:     std::string Comment = PP.getSpelling(Tok);
                        0: branch 1 not taken
                    15608: branch 2 taken
     186            15608:     if (Comment.empty()) continue;
     187                 : 
     188                 :     // Find all expected errors.
     189                 :     FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
     190            15608:                     Tok.getLocation(), "expected-error");
     191                 : 
     192                 :     // Find all expected warnings.
     193                 :     FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
     194            15608:                     Tok.getLocation(), "expected-warning");
     195                 : 
     196                 :     // Find all expected notes.
     197                 :     FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
     198            15608:                     Tok.getLocation(), "expected-note");
     199             1312:   };
     200                 : }
     201                 : 
     202                 : /// PrintProblem - This takes a diagnostic map of the delta between expected and
     203                 : /// seen diagnostics. If there's anything in it, then something unexpected
     204                 : /// happened. Print the map out in a nice format and return "true". If the map
     205                 : /// is empty and we're not going to print things, then return "false".
     206                 : ///
     207                 : static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
     208                 :                              const_diag_iterator diag_begin,
     209                 :                              const_diag_iterator diag_end,
     210            15744:                              const char *Kind, bool Expected) {
                    15727: branch 1 taken
                       17: branch 2 taken
     211            15744:   if (diag_begin == diag_end) return 0;
     212                 : 
     213               17:   llvm::SmallString<256> Fmt;
     214               17:   llvm::raw_svector_ostream OS(Fmt);
                       41: branch 2 taken
                       17: branch 3 taken
     215               58:   for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
                       41: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                       41: branch 5 taken
                        0: branch 6 not taken
                       41: branch 7 taken
     216               41:     if (I->first.isInvalid() || !SourceMgr)
     217                0:       OS << "\n  (frontend)";
     218                 :     else
     219               41:       OS << "\n  Line " << SourceMgr->getInstantiationLineNumber(I->first);
     220               41:     OS << ": " << I->second;
     221                 :   }
     222                 : 
     223                 :   Diags.Report(diag::err_verify_inconsistent_diags)
     224               17:     << Kind << !Expected << OS.str();
     225               17:   return std::distance(diag_begin, diag_end);
     226                 : }
     227                 : 
     228                 : /// CompareDiagLists - Compare two diagnostic lists and return the difference
     229                 : /// between them.
     230                 : ///
     231                 : static unsigned CompareDiagLists(Diagnostic &Diags,
     232                 :                                  SourceManager &SourceMgr,
     233                 :                                  const_diag_iterator d1_begin,
     234                 :                                  const_diag_iterator d1_end,
     235                 :                                  const_diag_iterator d2_begin,
     236                 :                                  const_diag_iterator d2_end,
     237             3936:                                  const char *Label) {
     238             3936:   DiagList LeftOnly;
     239             3936:   DiagList Left(d1_begin, d1_end);
     240             3936:   DiagList Right(d2_begin, d2_end);
     241                 : 
                     7095: branch 6 taken
                     3936: branch 7 taken
     242            11031:   for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
     243             7095:     unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
     244             7095:     const std::string &Diag1 = I->second;
     245                 : 
     246             7095:     DiagList::iterator II, IE;
                     8922: branch 4 taken
                       19: branch 5 taken
     247             8941:     for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
     248             8922:       unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
                     7135: branch 0 taken
                     1787: branch 1 taken
     249             8922:       if (LineNo1 != LineNo2) continue;
     250                 : 
     251             7135:       const std::string &Diag2 = II->second;
                      201: branch 1 taken
                     6934: branch 2 taken
                      142: branch 4 taken
                       59: branch 5 taken
                     7076: branch 6 taken
                       59: branch 7 taken
     252             7135:       if (Diag2.find(Diag1) != std::string::npos ||
     253                 :           Diag1.find(Diag2) != std::string::npos) {
     254             7076:         break;
     255                 :       }
     256                 :     }
                       19: branch 1 taken
                     7076: branch 2 taken
     257             7095:     if (II == IE) {
     258                 :       // Not found.
     259               19:       LeftOnly.push_back(*I);
     260                 :     } else {
     261                 :       // Found. The same cannot be found twice.
     262             7076:       Right.erase(II);
     263                 :     }
     264                 :   }
     265                 :   // Now all that's left in Right are those that were not matched.
     266                 : 
     267                 :   return (PrintProblem(Diags, &SourceMgr,
     268                 :                       LeftOnly.begin(), LeftOnly.end(), Label, true) +
     269                 :           PrintProblem(Diags, &SourceMgr,
     270             3936:                        Right.begin(), Right.end(), Label, false));
     271                 : }
     272                 : 
     273                 : /// CheckResults - This compares the expected results to those that
     274                 : /// were actually reported. It emits any discrepencies. Return "true" if there
     275                 : /// were problems. Return "false" otherwise.
     276                 : ///
     277                 : static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
     278                 :                              const TextDiagnosticBuffer &Buffer,
     279                 :                              const DiagList &ExpectedErrors,
     280                 :                              const DiagList &ExpectedWarnings,
     281             1312:                              const DiagList &ExpectedNotes) {
     282                 :   // We want to capture the delta between what was expected and what was
     283                 :   // seen.
     284                 :   //
     285                 :   //   Expected \ Seen - set expected but not seen
     286                 :   //   Seen \ Expected - set seen but not expected
     287             1312:   unsigned NumProblems = 0;
     288                 : 
     289                 :   // See if there are error mismatches.
     290                 :   NumProblems += CompareDiagLists(Diags, SourceMgr,
     291                 :                                   ExpectedErrors.begin(), ExpectedErrors.end(),
     292                 :                                   Buffer.err_begin(), Buffer.err_end(),
     293             1312:                                   "error");
     294                 : 
     295                 :   // See if there are warning mismatches.
     296                 :   NumProblems += CompareDiagLists(Diags, SourceMgr,
     297                 :                                   ExpectedWarnings.begin(),
     298                 :                                   ExpectedWarnings.end(),
     299                 :                                   Buffer.warn_begin(), Buffer.warn_end(),
     300             1312:                                   "warning");
     301                 : 
     302                 :   // See if there are note mismatches.
     303                 :   NumProblems += CompareDiagLists(Diags, SourceMgr,
     304                 :                                   ExpectedNotes.begin(),
     305                 :                                   ExpectedNotes.end(),
     306                 :                                   Buffer.note_begin(), Buffer.note_end(),
     307             1312:                                   "note");
     308                 : 
     309             1312:   return NumProblems;
     310                 : }
     311                 : 
     312                 : 
     313             3936: void VerifyDiagnosticsClient::CheckDiagnostics() {
     314             3936:   DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
     315                 : 
     316                 :   // Ensure any diagnostics go to the primary client.
     317             3936:   DiagnosticClient *CurClient = Diags.getClient();
     318             3936:   Diags.setClient(PrimaryClient.get());
     319                 : 
     320                 :   // If we have a preprocessor, scan the source for expected diagnostic
     321                 :   // markers. If not then any diagnostics are unexpected.
                     1312: branch 0 taken
                     2624: branch 1 taken
     322             3936:   if (CurrentPreprocessor) {
     323                 :     FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings,
     324             1312:                       ExpectedNotes);
     325                 : 
     326                 :     // Check that the expected diagnostics occurred.
     327                 :     NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
     328                 :                               *Buffer,
     329             1312:                               ExpectedErrors, ExpectedWarnings, ExpectedNotes);
     330                 :   } else {
     331                 :     NumErrors += (PrintProblem(Diags, 0,
     332                 :                                Buffer->err_begin(), Buffer->err_end(),
     333                 :                                "error", false) +
     334                 :                   PrintProblem(Diags, 0,
     335                 :                                Buffer->warn_begin(), Buffer->warn_end(),
     336                 :                                "warn", false) +
     337                 :                   PrintProblem(Diags, 0,
     338                 :                                Buffer->note_begin(), Buffer->note_end(),
     339             2624:                                "note", false));
     340                 :   }
     341                 : 
     342             3936:   Diags.setClient(CurClient);
     343                 : 
     344                 :   // Reset the buffer, we have processed all the diagnostics in it.
     345             3936:   Buffer.reset(new TextDiagnosticBuffer());
     346             3936: }

Generated: 2010-02-10 01:31 by zcov