xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
10b57cec5SDimitry Andric //===- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This is a concrete diagnostic client, which buffers the diagnostic messages.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/Frontend/VerifyDiagnosticConsumer.h"
140b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
150b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h"
160b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h"
170b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
180b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
190b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
200b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
210b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.h"
220b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
230b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticBuffer.h"
240b57cec5SDimitry Andric #include "clang/Lex/HeaderSearch.h"
250b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
260b57cec5SDimitry Andric #include "clang/Lex/PPCallbacks.h"
270b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
280b57cec5SDimitry Andric #include "clang/Lex/Token.h"
290b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
300b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
310b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
320b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
330b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
340b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
350b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
370b57cec5SDimitry Andric #include <algorithm>
380b57cec5SDimitry Andric #include <cassert>
390b57cec5SDimitry Andric #include <cstddef>
400b57cec5SDimitry Andric #include <cstring>
410b57cec5SDimitry Andric #include <iterator>
420b57cec5SDimitry Andric #include <memory>
430b57cec5SDimitry Andric #include <string>
440b57cec5SDimitry Andric #include <utility>
450b57cec5SDimitry Andric #include <vector>
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric using namespace clang;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric using Directive = VerifyDiagnosticConsumer::Directive;
500b57cec5SDimitry Andric using DirectiveList = VerifyDiagnosticConsumer::DirectiveList;
510b57cec5SDimitry Andric using ExpectedData = VerifyDiagnosticConsumer::ExpectedData;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric #ifndef NDEBUG
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric namespace {
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric class VerifyFileTracker : public PPCallbacks {
580b57cec5SDimitry Andric   VerifyDiagnosticConsumer &Verify;
590b57cec5SDimitry Andric   SourceManager &SM;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric public:
620b57cec5SDimitry Andric   VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
630b57cec5SDimitry Andric       : Verify(Verify), SM(SM) {}
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   /// Hook into the preprocessor and update the list of parsed
660b57cec5SDimitry Andric   /// files when the preprocessor indicates a new file is entered.
670b57cec5SDimitry Andric   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
680b57cec5SDimitry Andric                    SrcMgr::CharacteristicKind FileType,
690b57cec5SDimitry Andric                    FileID PrevFID) override {
700b57cec5SDimitry Andric     Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
710b57cec5SDimitry Andric                                   VerifyDiagnosticConsumer::IsParsed);
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric } // namespace
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric #endif
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
800b57cec5SDimitry Andric // Checking diagnostics implementation.
810b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric using DiagList = TextDiagnosticBuffer::DiagList;
840b57cec5SDimitry Andric using const_diag_iterator = TextDiagnosticBuffer::const_iterator;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric namespace {
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric /// StandardDirective - Directive with string matching.
890b57cec5SDimitry Andric class StandardDirective : public Directive {
900b57cec5SDimitry Andric public:
910b57cec5SDimitry Andric   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
925ffd83dbSDimitry Andric                     bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
935ffd83dbSDimitry Andric                     unsigned Min, unsigned Max)
945ffd83dbSDimitry Andric       : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
955ffd83dbSDimitry Andric                   MatchAnyLine, Text, Min, Max) {}
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   bool isValid(std::string &Error) override {
980b57cec5SDimitry Andric     // all strings are considered valid; even empty ones
990b57cec5SDimitry Andric     return true;
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric 
102349cc55cSDimitry Andric   bool match(StringRef S) override { return S.contains(Text); }
1030b57cec5SDimitry Andric };
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric /// RegexDirective - Directive with regular-expression matching.
1060b57cec5SDimitry Andric class RegexDirective : public Directive {
1070b57cec5SDimitry Andric public:
1080b57cec5SDimitry Andric   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
1095ffd83dbSDimitry Andric                  bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
1105ffd83dbSDimitry Andric                  unsigned Min, unsigned Max, StringRef RegexStr)
1115ffd83dbSDimitry Andric       : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
1125ffd83dbSDimitry Andric                   MatchAnyLine, Text, Min, Max),
1130b57cec5SDimitry Andric         Regex(RegexStr) {}
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   bool isValid(std::string &Error) override {
1160b57cec5SDimitry Andric     return Regex.isValid(Error);
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   bool match(StringRef S) override {
1200b57cec5SDimitry Andric     return Regex.match(S);
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric private:
1240b57cec5SDimitry Andric   llvm::Regex Regex;
1250b57cec5SDimitry Andric };
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric class ParseHelper
1280b57cec5SDimitry Andric {
1290b57cec5SDimitry Andric public:
1300b57cec5SDimitry Andric   ParseHelper(StringRef S)
1310b57cec5SDimitry Andric       : Begin(S.begin()), End(S.end()), C(Begin), P(Begin) {}
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   // Return true if string literal is next.
1340b57cec5SDimitry Andric   bool Next(StringRef S) {
1350b57cec5SDimitry Andric     P = C;
1360b57cec5SDimitry Andric     PEnd = C + S.size();
1370b57cec5SDimitry Andric     if (PEnd > End)
1380b57cec5SDimitry Andric       return false;
1390b57cec5SDimitry Andric     return memcmp(P, S.data(), S.size()) == 0;
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Return true if number is next.
1430b57cec5SDimitry Andric   // Output N only if number is next.
1440b57cec5SDimitry Andric   bool Next(unsigned &N) {
1450b57cec5SDimitry Andric     unsigned TMP = 0;
1460b57cec5SDimitry Andric     P = C;
1470b57cec5SDimitry Andric     PEnd = P;
1480b57cec5SDimitry Andric     for (; PEnd < End && *PEnd >= '0' && *PEnd <= '9'; ++PEnd) {
1490b57cec5SDimitry Andric       TMP *= 10;
1500b57cec5SDimitry Andric       TMP += *PEnd - '0';
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric     if (PEnd == C)
1530b57cec5SDimitry Andric       return false;
1540b57cec5SDimitry Andric     N = TMP;
1550b57cec5SDimitry Andric     return true;
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   // Return true if a marker is next.
1590b57cec5SDimitry Andric   // A marker is the longest match for /#[A-Za-z0-9_-]+/.
1600b57cec5SDimitry Andric   bool NextMarker() {
1610b57cec5SDimitry Andric     P = C;
1620b57cec5SDimitry Andric     if (P == End || *P != '#')
1630b57cec5SDimitry Andric       return false;
1640b57cec5SDimitry Andric     PEnd = P;
1650b57cec5SDimitry Andric     ++PEnd;
1660b57cec5SDimitry Andric     while ((isAlphanumeric(*PEnd) || *PEnd == '-' || *PEnd == '_') &&
1670b57cec5SDimitry Andric            PEnd < End)
1680b57cec5SDimitry Andric       ++PEnd;
1690b57cec5SDimitry Andric     return PEnd > P + 1;
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // Return true if string literal S is matched in content.
1730b57cec5SDimitry Andric   // When true, P marks begin-position of the match, and calling Advance sets C
1740b57cec5SDimitry Andric   // to end-position of the match.
1750b57cec5SDimitry Andric   // If S is the empty string, then search for any letter instead (makes sense
1760b57cec5SDimitry Andric   // with FinishDirectiveToken=true).
1770b57cec5SDimitry Andric   // If EnsureStartOfWord, then skip matches that don't start a new word.
1780b57cec5SDimitry Andric   // If FinishDirectiveToken, then assume the match is the start of a comment
1790b57cec5SDimitry Andric   // directive for -verify, and extend the match to include the entire first
1800b57cec5SDimitry Andric   // token of that directive.
1810b57cec5SDimitry Andric   bool Search(StringRef S, bool EnsureStartOfWord = false,
1820b57cec5SDimitry Andric               bool FinishDirectiveToken = false) {
1830b57cec5SDimitry Andric     do {
1840b57cec5SDimitry Andric       if (!S.empty()) {
1850b57cec5SDimitry Andric         P = std::search(C, End, S.begin(), S.end());
1860b57cec5SDimitry Andric         PEnd = P + S.size();
1870b57cec5SDimitry Andric       }
1880b57cec5SDimitry Andric       else {
1890b57cec5SDimitry Andric         P = C;
1900b57cec5SDimitry Andric         while (P != End && !isLetter(*P))
1910b57cec5SDimitry Andric           ++P;
1920b57cec5SDimitry Andric         PEnd = P + 1;
1930b57cec5SDimitry Andric       }
1940b57cec5SDimitry Andric       if (P == End)
1950b57cec5SDimitry Andric         break;
1960b57cec5SDimitry Andric       // If not start of word but required, skip and search again.
1970b57cec5SDimitry Andric       if (EnsureStartOfWord
1980b57cec5SDimitry Andric                // Check if string literal starts a new word.
1990b57cec5SDimitry Andric           && !(P == Begin || isWhitespace(P[-1])
2000b57cec5SDimitry Andric                // Or it could be preceded by the start of a comment.
2010b57cec5SDimitry Andric                || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
2020b57cec5SDimitry Andric                                    &&  P[-2] == '/')))
2030b57cec5SDimitry Andric         continue;
2040b57cec5SDimitry Andric       if (FinishDirectiveToken) {
2050b57cec5SDimitry Andric         while (PEnd != End && (isAlphanumeric(*PEnd)
2060b57cec5SDimitry Andric                                || *PEnd == '-' || *PEnd == '_'))
2070b57cec5SDimitry Andric           ++PEnd;
2080b57cec5SDimitry Andric         // Put back trailing digits and hyphens to be parsed later as a count
2090b57cec5SDimitry Andric         // or count range.  Because -verify prefixes must start with letters,
2100b57cec5SDimitry Andric         // we know the actual directive we found starts with a letter, so
2110b57cec5SDimitry Andric         // we won't put back the entire directive word and thus record an empty
2120b57cec5SDimitry Andric         // string.
2130b57cec5SDimitry Andric         assert(isLetter(*P) && "-verify prefix must start with a letter");
2140b57cec5SDimitry Andric         while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
2150b57cec5SDimitry Andric           --PEnd;
2160b57cec5SDimitry Andric       }
2170b57cec5SDimitry Andric       return true;
2180b57cec5SDimitry Andric     } while (Advance());
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   // Return true if a CloseBrace that closes the OpenBrace at the current nest
2230b57cec5SDimitry Andric   // level is found. When true, P marks begin-position of CloseBrace.
2240b57cec5SDimitry Andric   bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
2250b57cec5SDimitry Andric     unsigned Depth = 1;
2260b57cec5SDimitry Andric     P = C;
2270b57cec5SDimitry Andric     while (P < End) {
2280b57cec5SDimitry Andric       StringRef S(P, End - P);
2295f757f3fSDimitry Andric       if (S.starts_with(OpenBrace)) {
2300b57cec5SDimitry Andric         ++Depth;
2310b57cec5SDimitry Andric         P += OpenBrace.size();
2325f757f3fSDimitry Andric       } else if (S.starts_with(CloseBrace)) {
2330b57cec5SDimitry Andric         --Depth;
2340b57cec5SDimitry Andric         if (Depth == 0) {
2350b57cec5SDimitry Andric           PEnd = P + CloseBrace.size();
2360b57cec5SDimitry Andric           return true;
2370b57cec5SDimitry Andric         }
2380b57cec5SDimitry Andric         P += CloseBrace.size();
2390b57cec5SDimitry Andric       } else {
2400b57cec5SDimitry Andric         ++P;
2410b57cec5SDimitry Andric       }
2420b57cec5SDimitry Andric     }
2430b57cec5SDimitry Andric     return false;
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   // Advance 1-past previous next/search.
2470b57cec5SDimitry Andric   // Behavior is undefined if previous next/search failed.
2480b57cec5SDimitry Andric   bool Advance() {
2490b57cec5SDimitry Andric     C = PEnd;
2500b57cec5SDimitry Andric     return C < End;
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   // Return the text matched by the previous next/search.
2540b57cec5SDimitry Andric   // Behavior is undefined if previous next/search failed.
2550b57cec5SDimitry Andric   StringRef Match() { return StringRef(P, PEnd - P); }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   // Skip zero or more whitespace.
2580b57cec5SDimitry Andric   void SkipWhitespace() {
2590b57cec5SDimitry Andric     for (; C < End && isWhitespace(*C); ++C)
2600b57cec5SDimitry Andric       ;
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   // Return true if EOF reached.
2640b57cec5SDimitry Andric   bool Done() {
2650b57cec5SDimitry Andric     return !(C < End);
2660b57cec5SDimitry Andric   }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   // Beginning of expected content.
2690b57cec5SDimitry Andric   const char * const Begin;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   // End of expected content (1-past).
2720b57cec5SDimitry Andric   const char * const End;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   // Position of next char in content.
2750b57cec5SDimitry Andric   const char *C;
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   // Previous next/search subject start.
2780b57cec5SDimitry Andric   const char *P;
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric private:
2810b57cec5SDimitry Andric   // Previous next/search subject end (1-past).
2820b57cec5SDimitry Andric   const char *PEnd = nullptr;
2830b57cec5SDimitry Andric };
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric // The information necessary to create a directive.
2860b57cec5SDimitry Andric struct UnattachedDirective {
2870b57cec5SDimitry Andric   DirectiveList *DL = nullptr;
2880b57cec5SDimitry Andric   bool RegexKind = false;
2890b57cec5SDimitry Andric   SourceLocation DirectivePos, ContentBegin;
2900b57cec5SDimitry Andric   std::string Text;
2910b57cec5SDimitry Andric   unsigned Min = 1, Max = 1;
2920b57cec5SDimitry Andric };
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric // Attach the specified directive to the line of code indicated by
2950b57cec5SDimitry Andric // \p ExpectedLoc.
2960b57cec5SDimitry Andric void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
2975ffd83dbSDimitry Andric                      SourceLocation ExpectedLoc,
2985ffd83dbSDimitry Andric                      bool MatchAnyFileAndLine = false,
2995ffd83dbSDimitry Andric                      bool MatchAnyLine = false) {
3000b57cec5SDimitry Andric   // Construct new directive.
3015ffd83dbSDimitry Andric   std::unique_ptr<Directive> D = Directive::create(
3025ffd83dbSDimitry Andric       UD.RegexKind, UD.DirectivePos, ExpectedLoc, MatchAnyFileAndLine,
3030b57cec5SDimitry Andric       MatchAnyLine, UD.Text, UD.Min, UD.Max);
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   std::string Error;
3060b57cec5SDimitry Andric   if (!D->isValid(Error)) {
3070b57cec5SDimitry Andric     Diags.Report(UD.ContentBegin, diag::err_verify_invalid_content)
3080b57cec5SDimitry Andric       << (UD.RegexKind ? "regex" : "string") << Error;
3090b57cec5SDimitry Andric   }
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric   UD.DL->push_back(std::move(D));
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric } // anonymous
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric // Tracker for markers in the input files. A marker is a comment of the form
3170b57cec5SDimitry Andric //
3180b57cec5SDimitry Andric //   n = 123; // #123
3190b57cec5SDimitry Andric //
3200b57cec5SDimitry Andric // ... that can be referred to by a later expected-* directive:
3210b57cec5SDimitry Andric //
3220b57cec5SDimitry Andric //   // expected-error@#123 {{undeclared identifier 'n'}}
3230b57cec5SDimitry Andric //
3240b57cec5SDimitry Andric // Marker declarations must be at the start of a comment or preceded by
3250b57cec5SDimitry Andric // whitespace to distinguish them from uses of markers in directives.
3260b57cec5SDimitry Andric class VerifyDiagnosticConsumer::MarkerTracker {
3270b57cec5SDimitry Andric   DiagnosticsEngine &Diags;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   struct Marker {
3300b57cec5SDimitry Andric     SourceLocation DefLoc;
3310b57cec5SDimitry Andric     SourceLocation RedefLoc;
3320b57cec5SDimitry Andric     SourceLocation UseLoc;
3330b57cec5SDimitry Andric   };
3340b57cec5SDimitry Andric   llvm::StringMap<Marker> Markers;
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   // Directives that couldn't be created yet because they name an unknown
3370b57cec5SDimitry Andric   // marker.
3380b57cec5SDimitry Andric   llvm::StringMap<llvm::SmallVector<UnattachedDirective, 2>> DeferredDirectives;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric public:
3410b57cec5SDimitry Andric   MarkerTracker(DiagnosticsEngine &Diags) : Diags(Diags) {}
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   // Register a marker.
3440b57cec5SDimitry Andric   void addMarker(StringRef MarkerName, SourceLocation Pos) {
3450b57cec5SDimitry Andric     auto InsertResult = Markers.insert(
3460b57cec5SDimitry Andric         {MarkerName, Marker{Pos, SourceLocation(), SourceLocation()}});
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric     Marker &M = InsertResult.first->second;
3490b57cec5SDimitry Andric     if (!InsertResult.second) {
3500b57cec5SDimitry Andric       // Marker was redefined.
3510b57cec5SDimitry Andric       M.RedefLoc = Pos;
3520b57cec5SDimitry Andric     } else {
3530b57cec5SDimitry Andric       // First definition: build any deferred directives.
3540b57cec5SDimitry Andric       auto Deferred = DeferredDirectives.find(MarkerName);
3550b57cec5SDimitry Andric       if (Deferred != DeferredDirectives.end()) {
3560b57cec5SDimitry Andric         for (auto &UD : Deferred->second) {
3570b57cec5SDimitry Andric           if (M.UseLoc.isInvalid())
3580b57cec5SDimitry Andric             M.UseLoc = UD.DirectivePos;
3590b57cec5SDimitry Andric           attachDirective(Diags, UD, Pos);
3600b57cec5SDimitry Andric         }
3610b57cec5SDimitry Andric         DeferredDirectives.erase(Deferred);
3620b57cec5SDimitry Andric       }
3630b57cec5SDimitry Andric     }
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   // Register a directive at the specified marker.
3670b57cec5SDimitry Andric   void addDirective(StringRef MarkerName, const UnattachedDirective &UD) {
3680b57cec5SDimitry Andric     auto MarkerIt = Markers.find(MarkerName);
3690b57cec5SDimitry Andric     if (MarkerIt != Markers.end()) {
3700b57cec5SDimitry Andric       Marker &M = MarkerIt->second;
3710b57cec5SDimitry Andric       if (M.UseLoc.isInvalid())
3720b57cec5SDimitry Andric         M.UseLoc = UD.DirectivePos;
3730b57cec5SDimitry Andric       return attachDirective(Diags, UD, M.DefLoc);
3740b57cec5SDimitry Andric     }
3750b57cec5SDimitry Andric     DeferredDirectives[MarkerName].push_back(UD);
3760b57cec5SDimitry Andric   }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   // Ensure we have no remaining deferred directives, and no
3790b57cec5SDimitry Andric   // multiply-defined-and-used markers.
3800b57cec5SDimitry Andric   void finalize() {
3810b57cec5SDimitry Andric     for (auto &MarkerInfo : Markers) {
3820b57cec5SDimitry Andric       StringRef Name = MarkerInfo.first();
3830b57cec5SDimitry Andric       Marker &M = MarkerInfo.second;
3840b57cec5SDimitry Andric       if (M.RedefLoc.isValid() && M.UseLoc.isValid()) {
3850b57cec5SDimitry Andric         Diags.Report(M.UseLoc, diag::err_verify_ambiguous_marker) << Name;
3860b57cec5SDimitry Andric         Diags.Report(M.DefLoc, diag::note_verify_ambiguous_marker) << Name;
3870b57cec5SDimitry Andric         Diags.Report(M.RedefLoc, diag::note_verify_ambiguous_marker) << Name;
3880b57cec5SDimitry Andric       }
3890b57cec5SDimitry Andric     }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric     for (auto &DeferredPair : DeferredDirectives) {
3920b57cec5SDimitry Andric       Diags.Report(DeferredPair.second.front().DirectivePos,
3930b57cec5SDimitry Andric                    diag::err_verify_no_such_marker)
3940b57cec5SDimitry Andric           << DeferredPair.first();
3950b57cec5SDimitry Andric     }
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric };
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric /// ParseDirective - Go through the comment and see if it indicates expected
4000b57cec5SDimitry Andric /// diagnostics. If so, then put them in the appropriate directive list.
4010b57cec5SDimitry Andric ///
4020b57cec5SDimitry Andric /// Returns true if any valid directives were found.
4030b57cec5SDimitry Andric static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
4040b57cec5SDimitry Andric                            Preprocessor *PP, SourceLocation Pos,
4050b57cec5SDimitry Andric                            VerifyDiagnosticConsumer::DirectiveStatus &Status,
4060b57cec5SDimitry Andric                            VerifyDiagnosticConsumer::MarkerTracker &Markers) {
4070b57cec5SDimitry Andric   DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   // First, scan the comment looking for markers.
4100b57cec5SDimitry Andric   for (ParseHelper PH(S); !PH.Done();) {
4110b57cec5SDimitry Andric     if (!PH.Search("#", true))
4120b57cec5SDimitry Andric       break;
4130b57cec5SDimitry Andric     PH.C = PH.P;
4140b57cec5SDimitry Andric     if (!PH.NextMarker()) {
4150b57cec5SDimitry Andric       PH.Next("#");
4160b57cec5SDimitry Andric       PH.Advance();
4170b57cec5SDimitry Andric       continue;
4180b57cec5SDimitry Andric     }
4190b57cec5SDimitry Andric     PH.Advance();
4200b57cec5SDimitry Andric     Markers.addMarker(PH.Match(), Pos);
4210b57cec5SDimitry Andric   }
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   // A single comment may contain multiple directives.
4240b57cec5SDimitry Andric   bool FoundDirective = false;
4250b57cec5SDimitry Andric   for (ParseHelper PH(S); !PH.Done();) {
4260b57cec5SDimitry Andric     // Search for the initial directive token.
4270b57cec5SDimitry Andric     // If one prefix, save time by searching only for its directives.
4280b57cec5SDimitry Andric     // Otherwise, search for any potential directive token and check it later.
4290b57cec5SDimitry Andric     const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
4300b57cec5SDimitry Andric     if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
4310b57cec5SDimitry Andric                                : PH.Search("", true, true)))
4320b57cec5SDimitry Andric       break;
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric     StringRef DToken = PH.Match();
4350b57cec5SDimitry Andric     PH.Advance();
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric     // Default directive kind.
4380b57cec5SDimitry Andric     UnattachedDirective D;
4390b57cec5SDimitry Andric     const char *KindStr = "string";
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric     // Parse the initial directive token in reverse so we can easily determine
4420b57cec5SDimitry Andric     // its exact actual prefix.  If we were to parse it from the front instead,
4430b57cec5SDimitry Andric     // it would be harder to determine where the prefix ends because there
4440b57cec5SDimitry Andric     // might be multiple matching -verify prefixes because some might prefix
4450b57cec5SDimitry Andric     // others.
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric     // Regex in initial directive token: -re
4485f757f3fSDimitry Andric     if (DToken.ends_with("-re")) {
4490b57cec5SDimitry Andric       D.RegexKind = true;
4500b57cec5SDimitry Andric       KindStr = "regex";
4510b57cec5SDimitry Andric       DToken = DToken.substr(0, DToken.size()-3);
4520b57cec5SDimitry Andric     }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric     // Type in initial directive token: -{error|warning|note|no-diagnostics}
4550b57cec5SDimitry Andric     bool NoDiag = false;
4560b57cec5SDimitry Andric     StringRef DType;
4575f757f3fSDimitry Andric     if (DToken.ends_with(DType = "-error"))
4580b57cec5SDimitry Andric       D.DL = ED ? &ED->Errors : nullptr;
4595f757f3fSDimitry Andric     else if (DToken.ends_with(DType = "-warning"))
4600b57cec5SDimitry Andric       D.DL = ED ? &ED->Warnings : nullptr;
4615f757f3fSDimitry Andric     else if (DToken.ends_with(DType = "-remark"))
4620b57cec5SDimitry Andric       D.DL = ED ? &ED->Remarks : nullptr;
4635f757f3fSDimitry Andric     else if (DToken.ends_with(DType = "-note"))
4640b57cec5SDimitry Andric       D.DL = ED ? &ED->Notes : nullptr;
4655f757f3fSDimitry Andric     else if (DToken.ends_with(DType = "-no-diagnostics")) {
4660b57cec5SDimitry Andric       NoDiag = true;
4670b57cec5SDimitry Andric       if (D.RegexKind)
4680b57cec5SDimitry Andric         continue;
4695f757f3fSDimitry Andric     } else
4700b57cec5SDimitry Andric       continue;
4710b57cec5SDimitry Andric     DToken = DToken.substr(0, DToken.size()-DType.size());
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric     // What's left in DToken is the actual prefix.  That might not be a -verify
4740b57cec5SDimitry Andric     // prefix even if there is only one -verify prefix (for example, the full
4750b57cec5SDimitry Andric     // DToken is foo-bar-warning, but foo is the only -verify prefix).
4760b57cec5SDimitry Andric     if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
4770b57cec5SDimitry Andric       continue;
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric     if (NoDiag) {
4800b57cec5SDimitry Andric       if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
4810b57cec5SDimitry Andric         Diags.Report(Pos, diag::err_verify_invalid_no_diags)
4820b57cec5SDimitry Andric           << /*IsExpectedNoDiagnostics=*/true;
4830b57cec5SDimitry Andric       else
4840b57cec5SDimitry Andric         Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
4850b57cec5SDimitry Andric       continue;
4860b57cec5SDimitry Andric     }
4870b57cec5SDimitry Andric     if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
4880b57cec5SDimitry Andric       Diags.Report(Pos, diag::err_verify_invalid_no_diags)
4890b57cec5SDimitry Andric         << /*IsExpectedNoDiagnostics=*/false;
4900b57cec5SDimitry Andric       continue;
4910b57cec5SDimitry Andric     }
4920b57cec5SDimitry Andric     Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric     // If a directive has been found but we're not interested
4950b57cec5SDimitry Andric     // in storing the directive information, return now.
4960b57cec5SDimitry Andric     if (!D.DL)
4970b57cec5SDimitry Andric       return true;
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric     // Next optional token: @
5000b57cec5SDimitry Andric     SourceLocation ExpectedLoc;
5010b57cec5SDimitry Andric     StringRef Marker;
5025ffd83dbSDimitry Andric     bool MatchAnyFileAndLine = false;
5030b57cec5SDimitry Andric     bool MatchAnyLine = false;
5040b57cec5SDimitry Andric     if (!PH.Next("@")) {
5050b57cec5SDimitry Andric       ExpectedLoc = Pos;
5060b57cec5SDimitry Andric     } else {
5070b57cec5SDimitry Andric       PH.Advance();
5080b57cec5SDimitry Andric       unsigned Line = 0;
5090b57cec5SDimitry Andric       bool FoundPlus = PH.Next("+");
5100b57cec5SDimitry Andric       if (FoundPlus || PH.Next("-")) {
5110b57cec5SDimitry Andric         // Relative to current line.
5120b57cec5SDimitry Andric         PH.Advance();
5130b57cec5SDimitry Andric         bool Invalid = false;
5140b57cec5SDimitry Andric         unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
5150b57cec5SDimitry Andric         if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
5160b57cec5SDimitry Andric           if (FoundPlus) ExpectedLine += Line;
5170b57cec5SDimitry Andric           else ExpectedLine -= Line;
5180b57cec5SDimitry Andric           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
5190b57cec5SDimitry Andric         }
5200b57cec5SDimitry Andric       } else if (PH.Next(Line)) {
5210b57cec5SDimitry Andric         // Absolute line number.
5220b57cec5SDimitry Andric         if (Line > 0)
5230b57cec5SDimitry Andric           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
5240b57cec5SDimitry Andric       } else if (PH.NextMarker()) {
5250b57cec5SDimitry Andric         Marker = PH.Match();
5260b57cec5SDimitry Andric       } else if (PP && PH.Search(":")) {
5270b57cec5SDimitry Andric         // Specific source file.
5280b57cec5SDimitry Andric         StringRef Filename(PH.C, PH.P-PH.C);
5290b57cec5SDimitry Andric         PH.Advance();
5300b57cec5SDimitry Andric 
5315ffd83dbSDimitry Andric         if (Filename == "*") {
5325ffd83dbSDimitry Andric           MatchAnyFileAndLine = true;
5335ffd83dbSDimitry Andric           if (!PH.Next("*")) {
5345ffd83dbSDimitry Andric             Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
5355ffd83dbSDimitry Andric                          diag::err_verify_missing_line)
5365ffd83dbSDimitry Andric                 << "'*'";
5375ffd83dbSDimitry Andric             continue;
5385ffd83dbSDimitry Andric           }
5395ffd83dbSDimitry Andric           MatchAnyLine = true;
5405ffd83dbSDimitry Andric           ExpectedLoc = SourceLocation();
5415ffd83dbSDimitry Andric         } else {
5420b57cec5SDimitry Andric           // Lookup file via Preprocessor, like a #include.
543bdd1243dSDimitry Andric           OptionalFileEntryRef File =
54404eeddc0SDimitry Andric               PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,
5450b57cec5SDimitry Andric                              nullptr, nullptr, nullptr, nullptr, nullptr);
546a7dea167SDimitry Andric           if (!File) {
5470b57cec5SDimitry Andric             Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
5485ffd83dbSDimitry Andric                          diag::err_verify_missing_file)
5495ffd83dbSDimitry Andric                 << Filename << KindStr;
5500b57cec5SDimitry Andric             continue;
5510b57cec5SDimitry Andric           }
5520b57cec5SDimitry Andric 
553e8d8bef9SDimitry Andric           FileID FID = SM.translateFile(*File);
554e8d8bef9SDimitry Andric           if (FID.isInvalid())
555e8d8bef9SDimitry Andric             FID = SM.createFileID(*File, Pos, SrcMgr::C_User);
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric           if (PH.Next(Line) && Line > 0)
558e8d8bef9SDimitry Andric             ExpectedLoc = SM.translateLineCol(FID, Line, 1);
5590b57cec5SDimitry Andric           else if (PH.Next("*")) {
5600b57cec5SDimitry Andric             MatchAnyLine = true;
561e8d8bef9SDimitry Andric             ExpectedLoc = SM.translateLineCol(FID, 1, 1);
5620b57cec5SDimitry Andric           }
5635ffd83dbSDimitry Andric         }
5640b57cec5SDimitry Andric       } else if (PH.Next("*")) {
5650b57cec5SDimitry Andric         MatchAnyLine = true;
5660b57cec5SDimitry Andric         ExpectedLoc = SourceLocation();
5670b57cec5SDimitry Andric       }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric       if (ExpectedLoc.isInvalid() && !MatchAnyLine && Marker.empty()) {
5700b57cec5SDimitry Andric         Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
5710b57cec5SDimitry Andric                      diag::err_verify_missing_line) << KindStr;
5720b57cec5SDimitry Andric         continue;
5730b57cec5SDimitry Andric       }
5740b57cec5SDimitry Andric       PH.Advance();
5750b57cec5SDimitry Andric     }
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric     // Skip optional whitespace.
5780b57cec5SDimitry Andric     PH.SkipWhitespace();
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric     // Next optional token: positive integer or a '+'.
5810b57cec5SDimitry Andric     if (PH.Next(D.Min)) {
5820b57cec5SDimitry Andric       PH.Advance();
5830b57cec5SDimitry Andric       // A positive integer can be followed by a '+' meaning min
5840b57cec5SDimitry Andric       // or more, or by a '-' meaning a range from min to max.
5850b57cec5SDimitry Andric       if (PH.Next("+")) {
5860b57cec5SDimitry Andric         D.Max = Directive::MaxCount;
5870b57cec5SDimitry Andric         PH.Advance();
5880b57cec5SDimitry Andric       } else if (PH.Next("-")) {
5890b57cec5SDimitry Andric         PH.Advance();
5900b57cec5SDimitry Andric         if (!PH.Next(D.Max) || D.Max < D.Min) {
5910b57cec5SDimitry Andric           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
5920b57cec5SDimitry Andric                        diag::err_verify_invalid_range) << KindStr;
5930b57cec5SDimitry Andric           continue;
5940b57cec5SDimitry Andric         }
5950b57cec5SDimitry Andric         PH.Advance();
5960b57cec5SDimitry Andric       } else {
5970b57cec5SDimitry Andric         D.Max = D.Min;
5980b57cec5SDimitry Andric       }
5990b57cec5SDimitry Andric     } else if (PH.Next("+")) {
6000b57cec5SDimitry Andric       // '+' on its own means "1 or more".
6010b57cec5SDimitry Andric       D.Max = Directive::MaxCount;
6020b57cec5SDimitry Andric       PH.Advance();
6030b57cec5SDimitry Andric     }
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric     // Skip optional whitespace.
6060b57cec5SDimitry Andric     PH.SkipWhitespace();
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric     // Next token: {{
6090b57cec5SDimitry Andric     if (!PH.Next("{{")) {
6100b57cec5SDimitry Andric       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
6110b57cec5SDimitry Andric                    diag::err_verify_missing_start) << KindStr;
6120b57cec5SDimitry Andric       continue;
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric     PH.Advance();
6150b57cec5SDimitry Andric     const char* const ContentBegin = PH.C; // mark content begin
6160b57cec5SDimitry Andric     // Search for token: }}
6170b57cec5SDimitry Andric     if (!PH.SearchClosingBrace("{{", "}}")) {
6180b57cec5SDimitry Andric       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
6190b57cec5SDimitry Andric                    diag::err_verify_missing_end) << KindStr;
6200b57cec5SDimitry Andric       continue;
6210b57cec5SDimitry Andric     }
6220b57cec5SDimitry Andric     const char* const ContentEnd = PH.P; // mark content end
6230b57cec5SDimitry Andric     PH.Advance();
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric     D.DirectivePos = Pos;
6260b57cec5SDimitry Andric     D.ContentBegin = Pos.getLocWithOffset(ContentBegin - PH.Begin);
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric     // Build directive text; convert \n to newlines.
6290b57cec5SDimitry Andric     StringRef NewlineStr = "\\n";
6300b57cec5SDimitry Andric     StringRef Content(ContentBegin, ContentEnd-ContentBegin);
6310b57cec5SDimitry Andric     size_t CPos = 0;
6320b57cec5SDimitry Andric     size_t FPos;
6330b57cec5SDimitry Andric     while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
6340b57cec5SDimitry Andric       D.Text += Content.substr(CPos, FPos-CPos);
6350b57cec5SDimitry Andric       D.Text += '\n';
6360b57cec5SDimitry Andric       CPos = FPos + NewlineStr.size();
6370b57cec5SDimitry Andric     }
6380b57cec5SDimitry Andric     if (D.Text.empty())
6390b57cec5SDimitry Andric       D.Text.assign(ContentBegin, ContentEnd);
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric     // Check that regex directives contain at least one regex.
6420b57cec5SDimitry Andric     if (D.RegexKind && D.Text.find("{{") == StringRef::npos) {
6430b57cec5SDimitry Andric       Diags.Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;
6440b57cec5SDimitry Andric       return false;
6450b57cec5SDimitry Andric     }
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric     if (Marker.empty())
6485ffd83dbSDimitry Andric       attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
6490b57cec5SDimitry Andric     else
6500b57cec5SDimitry Andric       Markers.addDirective(Marker, D);
6510b57cec5SDimitry Andric     FoundDirective = true;
6520b57cec5SDimitry Andric   }
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric   return FoundDirective;
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
6580b57cec5SDimitry Andric     : Diags(Diags_), PrimaryClient(Diags.getClient()),
6590b57cec5SDimitry Andric       PrimaryClientOwner(Diags.takeClient()),
6600b57cec5SDimitry Andric       Buffer(new TextDiagnosticBuffer()), Markers(new MarkerTracker(Diags)),
6610b57cec5SDimitry Andric       Status(HasNoDirectives) {
6620b57cec5SDimitry Andric   if (Diags.hasSourceManager())
6630b57cec5SDimitry Andric     setSourceManager(Diags.getSourceManager());
6640b57cec5SDimitry Andric }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
6670b57cec5SDimitry Andric   assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
6680b57cec5SDimitry Andric   assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
6690b57cec5SDimitry Andric   SrcManager = nullptr;
6700b57cec5SDimitry Andric   CheckDiagnostics();
6710b57cec5SDimitry Andric   assert(!Diags.ownsClient() &&
6720b57cec5SDimitry Andric          "The VerifyDiagnosticConsumer takes over ownership of the client!");
6730b57cec5SDimitry Andric }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric // DiagnosticConsumer interface.
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
6780b57cec5SDimitry Andric                                                const Preprocessor *PP) {
6790b57cec5SDimitry Andric   // Attach comment handler on first invocation.
6800b57cec5SDimitry Andric   if (++ActiveSourceFiles == 1) {
6810b57cec5SDimitry Andric     if (PP) {
6820b57cec5SDimitry Andric       CurrentPreprocessor = PP;
6830b57cec5SDimitry Andric       this->LangOpts = &LangOpts;
6840b57cec5SDimitry Andric       setSourceManager(PP->getSourceManager());
6850b57cec5SDimitry Andric       const_cast<Preprocessor *>(PP)->addCommentHandler(this);
6860b57cec5SDimitry Andric #ifndef NDEBUG
6870b57cec5SDimitry Andric       // Debug build tracks parsed files.
6880b57cec5SDimitry Andric       const_cast<Preprocessor *>(PP)->addPPCallbacks(
689a7dea167SDimitry Andric                       std::make_unique<VerifyFileTracker>(*this, *SrcManager));
6900b57cec5SDimitry Andric #endif
6910b57cec5SDimitry Andric     }
6920b57cec5SDimitry Andric   }
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric   assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
6950b57cec5SDimitry Andric   PrimaryClient->BeginSourceFile(LangOpts, PP);
6960b57cec5SDimitry Andric }
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric void VerifyDiagnosticConsumer::EndSourceFile() {
6990b57cec5SDimitry Andric   assert(ActiveSourceFiles && "No active source files!");
7000b57cec5SDimitry Andric   PrimaryClient->EndSourceFile();
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric   // Detach comment handler once last active source file completed.
7030b57cec5SDimitry Andric   if (--ActiveSourceFiles == 0) {
7040b57cec5SDimitry Andric     if (CurrentPreprocessor)
7050b57cec5SDimitry Andric       const_cast<Preprocessor *>(CurrentPreprocessor)->
7060b57cec5SDimitry Andric           removeCommentHandler(this);
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric     // Diagnose any used-but-not-defined markers.
7090b57cec5SDimitry Andric     Markers->finalize();
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric     // Check diagnostics once last file completed.
7120b57cec5SDimitry Andric     CheckDiagnostics();
7130b57cec5SDimitry Andric     CurrentPreprocessor = nullptr;
7140b57cec5SDimitry Andric     LangOpts = nullptr;
7150b57cec5SDimitry Andric   }
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric void VerifyDiagnosticConsumer::HandleDiagnostic(
7190b57cec5SDimitry Andric       DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
7200b57cec5SDimitry Andric   if (Info.hasSourceManager()) {
7210b57cec5SDimitry Andric     // If this diagnostic is for a different source manager, ignore it.
7220b57cec5SDimitry Andric     if (SrcManager && &Info.getSourceManager() != SrcManager)
7230b57cec5SDimitry Andric       return;
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric     setSourceManager(Info.getSourceManager());
7260b57cec5SDimitry Andric   }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric #ifndef NDEBUG
7290b57cec5SDimitry Andric   // Debug build tracks unparsed files for possible
7300b57cec5SDimitry Andric   // unparsed expected-* directives.
7310b57cec5SDimitry Andric   if (SrcManager) {
7320b57cec5SDimitry Andric     SourceLocation Loc = Info.getLocation();
7330b57cec5SDimitry Andric     if (Loc.isValid()) {
7340b57cec5SDimitry Andric       ParsedStatus PS = IsUnparsed;
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric       Loc = SrcManager->getExpansionLoc(Loc);
7370b57cec5SDimitry Andric       FileID FID = SrcManager->getFileID(Loc);
7380b57cec5SDimitry Andric 
73906c3fb27SDimitry Andric       auto FE = SrcManager->getFileEntryRefForID(FID);
7400b57cec5SDimitry Andric       if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
7410b57cec5SDimitry Andric         // If the file is a modules header file it shall not be parsed
7420b57cec5SDimitry Andric         // for expected-* directives.
7430b57cec5SDimitry Andric         HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
74406c3fb27SDimitry Andric         if (HS.findModuleForHeader(*FE))
7450b57cec5SDimitry Andric           PS = IsUnparsedNoDirectives;
7460b57cec5SDimitry Andric       }
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric       UpdateParsedFileStatus(*SrcManager, FID, PS);
7490b57cec5SDimitry Andric     }
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric #endif
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   // Send the diagnostic to the buffer, we will check it once we reach the end
7540b57cec5SDimitry Andric   // of the source file (or are destructed).
7550b57cec5SDimitry Andric   Buffer->HandleDiagnostic(DiagLevel, Info);
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric /// HandleComment - Hook into the preprocessor and extract comments containing
7590b57cec5SDimitry Andric ///  expected errors and warnings.
7600b57cec5SDimitry Andric bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
7610b57cec5SDimitry Andric                                              SourceRange Comment) {
7620b57cec5SDimitry Andric   SourceManager &SM = PP.getSourceManager();
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric   // If this comment is for a different source manager, ignore it.
7650b57cec5SDimitry Andric   if (SrcManager && &SM != SrcManager)
7660b57cec5SDimitry Andric     return false;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   SourceLocation CommentBegin = Comment.getBegin();
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   const char *CommentRaw = SM.getCharacterData(CommentBegin);
7710b57cec5SDimitry Andric   StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric   if (C.empty())
7740b57cec5SDimitry Andric     return false;
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   // Fold any "\<EOL>" sequences
7770b57cec5SDimitry Andric   size_t loc = C.find('\\');
7780b57cec5SDimitry Andric   if (loc == StringRef::npos) {
7790b57cec5SDimitry Andric     ParseDirective(C, &ED, SM, &PP, CommentBegin, Status, *Markers);
7800b57cec5SDimitry Andric     return false;
7810b57cec5SDimitry Andric   }
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric   std::string C2;
7840b57cec5SDimitry Andric   C2.reserve(C.size());
7850b57cec5SDimitry Andric 
7860b57cec5SDimitry Andric   for (size_t last = 0;; loc = C.find('\\', last)) {
7870b57cec5SDimitry Andric     if (loc == StringRef::npos || loc == C.size()) {
7880b57cec5SDimitry Andric       C2 += C.substr(last);
7890b57cec5SDimitry Andric       break;
7900b57cec5SDimitry Andric     }
7910b57cec5SDimitry Andric     C2 += C.substr(last, loc-last);
7920b57cec5SDimitry Andric     last = loc + 1;
7930b57cec5SDimitry Andric 
7940b57cec5SDimitry Andric     if (C[last] == '\n' || C[last] == '\r') {
7950b57cec5SDimitry Andric       ++last;
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric       // Escape \r\n  or \n\r, but not \n\n.
7980b57cec5SDimitry Andric       if (last < C.size())
7990b57cec5SDimitry Andric         if (C[last] == '\n' || C[last] == '\r')
8000b57cec5SDimitry Andric           if (C[last] != C[last-1])
8010b57cec5SDimitry Andric             ++last;
8020b57cec5SDimitry Andric     } else {
8030b57cec5SDimitry Andric       // This was just a normal backslash.
8040b57cec5SDimitry Andric       C2 += '\\';
8050b57cec5SDimitry Andric     }
8060b57cec5SDimitry Andric   }
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   if (!C2.empty())
8090b57cec5SDimitry Andric     ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status, *Markers);
8100b57cec5SDimitry Andric   return false;
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric #ifndef NDEBUG
8140b57cec5SDimitry Andric /// Lex the specified source file to determine whether it contains
8150b57cec5SDimitry Andric /// any expected-* directives.  As a Lexer is used rather than a full-blown
8160b57cec5SDimitry Andric /// Preprocessor, directives inside skipped #if blocks will still be found.
8170b57cec5SDimitry Andric ///
8180b57cec5SDimitry Andric /// \return true if any directives were found.
8190b57cec5SDimitry Andric static bool findDirectives(SourceManager &SM, FileID FID,
8200b57cec5SDimitry Andric                            const LangOptions &LangOpts) {
8210b57cec5SDimitry Andric   // Create a raw lexer to pull all the comments out of FID.
8220b57cec5SDimitry Andric   if (FID.isInvalid())
8230b57cec5SDimitry Andric     return false;
8240b57cec5SDimitry Andric 
8250b57cec5SDimitry Andric   // Create a lexer to lex all the tokens of the main file in raw mode.
826e8d8bef9SDimitry Andric   llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);
8270b57cec5SDimitry Andric   Lexer RawLex(FID, FromFile, SM, LangOpts);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   // Return comments as tokens, this is how we find expected diagnostics.
8300b57cec5SDimitry Andric   RawLex.SetCommentRetentionState(true);
8310b57cec5SDimitry Andric 
8320b57cec5SDimitry Andric   Token Tok;
8330b57cec5SDimitry Andric   Tok.setKind(tok::comment);
8340b57cec5SDimitry Andric   VerifyDiagnosticConsumer::DirectiveStatus Status =
8350b57cec5SDimitry Andric     VerifyDiagnosticConsumer::HasNoDirectives;
8360b57cec5SDimitry Andric   while (Tok.isNot(tok::eof)) {
8370b57cec5SDimitry Andric     RawLex.LexFromRawLexer(Tok);
8380b57cec5SDimitry Andric     if (!Tok.is(tok::comment)) continue;
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric     std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
8410b57cec5SDimitry Andric     if (Comment.empty()) continue;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric     // We don't care about tracking markers for this phase.
8440b57cec5SDimitry Andric     VerifyDiagnosticConsumer::MarkerTracker Markers(SM.getDiagnostics());
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric     // Find first directive.
8470b57cec5SDimitry Andric     if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
8480b57cec5SDimitry Andric                        Status, Markers))
8490b57cec5SDimitry Andric       return true;
8500b57cec5SDimitry Andric   }
8510b57cec5SDimitry Andric   return false;
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric #endif // !NDEBUG
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric /// Takes a list of diagnostics that have been generated but not matched
8560b57cec5SDimitry Andric /// by an expected-* directive and produces a diagnostic to the user from this.
8570b57cec5SDimitry Andric static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
8580b57cec5SDimitry Andric                                 const_diag_iterator diag_begin,
8590b57cec5SDimitry Andric                                 const_diag_iterator diag_end,
8600b57cec5SDimitry Andric                                 const char *Kind) {
8610b57cec5SDimitry Andric   if (diag_begin == diag_end) return 0;
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   SmallString<256> Fmt;
8640b57cec5SDimitry Andric   llvm::raw_svector_ostream OS(Fmt);
8650b57cec5SDimitry Andric   for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
8660b57cec5SDimitry Andric     if (I->first.isInvalid() || !SourceMgr)
8670b57cec5SDimitry Andric       OS << "\n  (frontend)";
8680b57cec5SDimitry Andric     else {
8690b57cec5SDimitry Andric       OS << "\n ";
8705f757f3fSDimitry Andric       if (OptionalFileEntryRef File =
8715f757f3fSDimitry Andric               SourceMgr->getFileEntryRefForID(SourceMgr->getFileID(I->first)))
8720b57cec5SDimitry Andric         OS << " File " << File->getName();
8730b57cec5SDimitry Andric       OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
8740b57cec5SDimitry Andric     }
8750b57cec5SDimitry Andric     OS << ": " << I->second;
8760b57cec5SDimitry Andric   }
8770b57cec5SDimitry Andric 
8785f757f3fSDimitry Andric   std::string Prefix = *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
8795f757f3fSDimitry Andric   std::string KindStr = Prefix + "-" + Kind;
8800b57cec5SDimitry Andric   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
8815f757f3fSDimitry Andric       << KindStr << /*Unexpected=*/true << OS.str();
8820b57cec5SDimitry Andric   return std::distance(diag_begin, diag_end);
8830b57cec5SDimitry Andric }
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric /// Takes a list of diagnostics that were expected to have been generated
8860b57cec5SDimitry Andric /// but were not and produces a diagnostic to the user from this.
8870b57cec5SDimitry Andric static unsigned PrintExpected(DiagnosticsEngine &Diags,
8880b57cec5SDimitry Andric                               SourceManager &SourceMgr,
8890b57cec5SDimitry Andric                               std::vector<Directive *> &DL, const char *Kind) {
8900b57cec5SDimitry Andric   if (DL.empty())
8910b57cec5SDimitry Andric     return 0;
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   SmallString<256> Fmt;
8940b57cec5SDimitry Andric   llvm::raw_svector_ostream OS(Fmt);
8950b57cec5SDimitry Andric   for (const auto *D : DL) {
8965ffd83dbSDimitry Andric     if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
8970b57cec5SDimitry Andric       OS << "\n  File *";
8980b57cec5SDimitry Andric     else
8990b57cec5SDimitry Andric       OS << "\n  File " << SourceMgr.getFilename(D->DiagnosticLoc);
9000b57cec5SDimitry Andric     if (D->MatchAnyLine)
9010b57cec5SDimitry Andric       OS << " Line *";
9020b57cec5SDimitry Andric     else
9030b57cec5SDimitry Andric       OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
9040b57cec5SDimitry Andric     if (D->DirectiveLoc != D->DiagnosticLoc)
9050b57cec5SDimitry Andric       OS << " (directive at "
9060b57cec5SDimitry Andric          << SourceMgr.getFilename(D->DirectiveLoc) << ':'
9070b57cec5SDimitry Andric          << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
9080b57cec5SDimitry Andric     OS << ": " << D->Text;
9090b57cec5SDimitry Andric   }
9100b57cec5SDimitry Andric 
9115f757f3fSDimitry Andric   std::string Prefix = *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
9125f757f3fSDimitry Andric   std::string KindStr = Prefix + "-" + Kind;
9130b57cec5SDimitry Andric   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
9145f757f3fSDimitry Andric       << KindStr << /*Unexpected=*/false << OS.str();
9150b57cec5SDimitry Andric   return DL.size();
9160b57cec5SDimitry Andric }
9170b57cec5SDimitry Andric 
9180b57cec5SDimitry Andric /// Determine whether two source locations come from the same file.
9190b57cec5SDimitry Andric static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
9200b57cec5SDimitry Andric                            SourceLocation DiagnosticLoc) {
9210b57cec5SDimitry Andric   while (DiagnosticLoc.isMacroID())
9220b57cec5SDimitry Andric     DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric   if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
9250b57cec5SDimitry Andric     return true;
9260b57cec5SDimitry Andric 
9270b57cec5SDimitry Andric   const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
9280b57cec5SDimitry Andric   if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
9290b57cec5SDimitry Andric     return true;
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
9320b57cec5SDimitry Andric }
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric /// CheckLists - Compare expected to seen diagnostic lists and return the
9350b57cec5SDimitry Andric /// the difference between them.
9360b57cec5SDimitry Andric static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
9370b57cec5SDimitry Andric                            const char *Label,
9380b57cec5SDimitry Andric                            DirectiveList &Left,
9390b57cec5SDimitry Andric                            const_diag_iterator d2_begin,
9400b57cec5SDimitry Andric                            const_diag_iterator d2_end,
9410b57cec5SDimitry Andric                            bool IgnoreUnexpected) {
9420b57cec5SDimitry Andric   std::vector<Directive *> LeftOnly;
9430b57cec5SDimitry Andric   DiagList Right(d2_begin, d2_end);
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric   for (auto &Owner : Left) {
9460b57cec5SDimitry Andric     Directive &D = *Owner;
9470b57cec5SDimitry Andric     unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric     for (unsigned i = 0; i < D.Max; ++i) {
9500b57cec5SDimitry Andric       DiagList::iterator II, IE;
9510b57cec5SDimitry Andric       for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
9520b57cec5SDimitry Andric         if (!D.MatchAnyLine) {
9530b57cec5SDimitry Andric           unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
9540b57cec5SDimitry Andric           if (LineNo1 != LineNo2)
9550b57cec5SDimitry Andric             continue;
9560b57cec5SDimitry Andric         }
9570b57cec5SDimitry Andric 
9585ffd83dbSDimitry Andric         if (!D.DiagnosticLoc.isInvalid() && !D.MatchAnyFileAndLine &&
9590b57cec5SDimitry Andric             !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
9600b57cec5SDimitry Andric           continue;
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric         const std::string &RightText = II->second;
9630b57cec5SDimitry Andric         if (D.match(RightText))
9640b57cec5SDimitry Andric           break;
9650b57cec5SDimitry Andric       }
9660b57cec5SDimitry Andric       if (II == IE) {
9670b57cec5SDimitry Andric         // Not found.
9680b57cec5SDimitry Andric         if (i >= D.Min) break;
9690b57cec5SDimitry Andric         LeftOnly.push_back(&D);
9700b57cec5SDimitry Andric       } else {
9710b57cec5SDimitry Andric         // Found. The same cannot be found twice.
9720b57cec5SDimitry Andric         Right.erase(II);
9730b57cec5SDimitry Andric       }
9740b57cec5SDimitry Andric     }
9750b57cec5SDimitry Andric   }
9760b57cec5SDimitry Andric   // Now all that's left in Right are those that were not matched.
9770b57cec5SDimitry Andric   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
9780b57cec5SDimitry Andric   if (!IgnoreUnexpected)
9790b57cec5SDimitry Andric     num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
9800b57cec5SDimitry Andric   return num;
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric /// CheckResults - This compares the expected results to those that
9840b57cec5SDimitry Andric /// were actually reported. It emits any discrepencies. Return "true" if there
9850b57cec5SDimitry Andric /// were problems. Return "false" otherwise.
9860b57cec5SDimitry Andric static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
9870b57cec5SDimitry Andric                              const TextDiagnosticBuffer &Buffer,
9880b57cec5SDimitry Andric                              ExpectedData &ED) {
9890b57cec5SDimitry Andric   // We want to capture the delta between what was expected and what was
9900b57cec5SDimitry Andric   // seen.
9910b57cec5SDimitry Andric   //
9920b57cec5SDimitry Andric   //   Expected \ Seen - set expected but not seen
9930b57cec5SDimitry Andric   //   Seen \ Expected - set seen but not expected
9940b57cec5SDimitry Andric   unsigned NumProblems = 0;
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric   const DiagnosticLevelMask DiagMask =
9970b57cec5SDimitry Andric     Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric   // See if there are error mismatches.
10000b57cec5SDimitry Andric   NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
10010b57cec5SDimitry Andric                             Buffer.err_begin(), Buffer.err_end(),
10020b57cec5SDimitry Andric                             bool(DiagnosticLevelMask::Error & DiagMask));
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric   // See if there are warning mismatches.
10050b57cec5SDimitry Andric   NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
10060b57cec5SDimitry Andric                             Buffer.warn_begin(), Buffer.warn_end(),
10070b57cec5SDimitry Andric                             bool(DiagnosticLevelMask::Warning & DiagMask));
10080b57cec5SDimitry Andric 
10090b57cec5SDimitry Andric   // See if there are remark mismatches.
10100b57cec5SDimitry Andric   NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
10110b57cec5SDimitry Andric                             Buffer.remark_begin(), Buffer.remark_end(),
10120b57cec5SDimitry Andric                             bool(DiagnosticLevelMask::Remark & DiagMask));
10130b57cec5SDimitry Andric 
10140b57cec5SDimitry Andric   // See if there are note mismatches.
10150b57cec5SDimitry Andric   NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
10160b57cec5SDimitry Andric                             Buffer.note_begin(), Buffer.note_end(),
10170b57cec5SDimitry Andric                             bool(DiagnosticLevelMask::Note & DiagMask));
10180b57cec5SDimitry Andric 
10190b57cec5SDimitry Andric   return NumProblems;
10200b57cec5SDimitry Andric }
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
10230b57cec5SDimitry Andric                                                       FileID FID,
10240b57cec5SDimitry Andric                                                       ParsedStatus PS) {
10250b57cec5SDimitry Andric   // Check SourceManager hasn't changed.
10260b57cec5SDimitry Andric   setSourceManager(SM);
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric #ifndef NDEBUG
10290b57cec5SDimitry Andric   if (FID.isInvalid())
10300b57cec5SDimitry Andric     return;
10310b57cec5SDimitry Andric 
10325f757f3fSDimitry Andric   OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID);
10330b57cec5SDimitry Andric 
10340b57cec5SDimitry Andric   if (PS == IsParsed) {
10350b57cec5SDimitry Andric     // Move the FileID from the unparsed set to the parsed set.
10360b57cec5SDimitry Andric     UnparsedFiles.erase(FID);
10375f757f3fSDimitry Andric     ParsedFiles.insert(std::make_pair(FID, FE ? &FE->getFileEntry() : nullptr));
10380b57cec5SDimitry Andric   } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
10390b57cec5SDimitry Andric     // Add the FileID to the unparsed set if we haven't seen it before.
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric     // Check for directives.
10420b57cec5SDimitry Andric     bool FoundDirectives;
10430b57cec5SDimitry Andric     if (PS == IsUnparsedNoDirectives)
10440b57cec5SDimitry Andric       FoundDirectives = false;
10450b57cec5SDimitry Andric     else
10460b57cec5SDimitry Andric       FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric     // Add the FileID to the unparsed set.
10490b57cec5SDimitry Andric     UnparsedFiles.insert(std::make_pair(FID,
10500b57cec5SDimitry Andric                                       UnparsedFileStatus(FE, FoundDirectives)));
10510b57cec5SDimitry Andric   }
10520b57cec5SDimitry Andric #endif
10530b57cec5SDimitry Andric }
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric void VerifyDiagnosticConsumer::CheckDiagnostics() {
10560b57cec5SDimitry Andric   // Ensure any diagnostics go to the primary client.
10570b57cec5SDimitry Andric   DiagnosticConsumer *CurClient = Diags.getClient();
10580b57cec5SDimitry Andric   std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
10590b57cec5SDimitry Andric   Diags.setClient(PrimaryClient, false);
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric #ifndef NDEBUG
10620b57cec5SDimitry Andric   // In a debug build, scan through any files that may have been missed
10630b57cec5SDimitry Andric   // during parsing and issue a fatal error if directives are contained
10640b57cec5SDimitry Andric   // within these files.  If a fatal error occurs, this suggests that
10650b57cec5SDimitry Andric   // this file is being parsed separately from the main file, in which
10660b57cec5SDimitry Andric   // case consider moving the directives to the correct place, if this
10670b57cec5SDimitry Andric   // is applicable.
10680b57cec5SDimitry Andric   if (!UnparsedFiles.empty()) {
10690b57cec5SDimitry Andric     // Generate a cache of parsed FileEntry pointers for alias lookups.
10700b57cec5SDimitry Andric     llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
10710b57cec5SDimitry Andric     for (const auto &I : ParsedFiles)
10720b57cec5SDimitry Andric       if (const FileEntry *FE = I.second)
10730b57cec5SDimitry Andric         ParsedFileCache.insert(FE);
10740b57cec5SDimitry Andric 
10750b57cec5SDimitry Andric     // Iterate through list of unparsed files.
10760b57cec5SDimitry Andric     for (const auto &I : UnparsedFiles) {
10770b57cec5SDimitry Andric       const UnparsedFileStatus &Status = I.second;
10785f757f3fSDimitry Andric       OptionalFileEntryRef FE = Status.getFile();
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric       // Skip files that have been parsed via an alias.
10815f757f3fSDimitry Andric       if (FE && ParsedFileCache.count(*FE))
10820b57cec5SDimitry Andric         continue;
10830b57cec5SDimitry Andric 
10840b57cec5SDimitry Andric       // Report a fatal error if this file contained directives.
10850b57cec5SDimitry Andric       if (Status.foundDirectives()) {
10865f757f3fSDimitry Andric         llvm::report_fatal_error("-verify directives found after rather"
10875f757f3fSDimitry Andric                                  " than during normal parsing of " +
10885f757f3fSDimitry Andric                                  (FE ? FE->getName() : "(unknown)"));
10890b57cec5SDimitry Andric       }
10900b57cec5SDimitry Andric     }
10910b57cec5SDimitry Andric 
10920b57cec5SDimitry Andric     // UnparsedFiles has been processed now, so clear it.
10930b57cec5SDimitry Andric     UnparsedFiles.clear();
10940b57cec5SDimitry Andric   }
10950b57cec5SDimitry Andric #endif // !NDEBUG
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric   if (SrcManager) {
10980b57cec5SDimitry Andric     // Produce an error if no expected-* directives could be found in the
10990b57cec5SDimitry Andric     // source file(s) processed.
11000b57cec5SDimitry Andric     if (Status == HasNoDirectives) {
11010b57cec5SDimitry Andric       Diags.Report(diag::err_verify_no_directives).setForceEmit();
11020b57cec5SDimitry Andric       ++NumErrors;
11030b57cec5SDimitry Andric       Status = HasNoDirectivesReported;
11040b57cec5SDimitry Andric     }
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric     // Check that the expected diagnostics occurred.
11070b57cec5SDimitry Andric     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
11080b57cec5SDimitry Andric   } else {
11090b57cec5SDimitry Andric     const DiagnosticLevelMask DiagMask =
11100b57cec5SDimitry Andric         ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
11110b57cec5SDimitry Andric     if (bool(DiagnosticLevelMask::Error & DiagMask))
11120b57cec5SDimitry Andric       NumErrors += PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
11130b57cec5SDimitry Andric                                    Buffer->err_end(), "error");
11140b57cec5SDimitry Andric     if (bool(DiagnosticLevelMask::Warning & DiagMask))
11150b57cec5SDimitry Andric       NumErrors += PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
11160b57cec5SDimitry Andric                                    Buffer->warn_end(), "warn");
11170b57cec5SDimitry Andric     if (bool(DiagnosticLevelMask::Remark & DiagMask))
11180b57cec5SDimitry Andric       NumErrors += PrintUnexpected(Diags, nullptr, Buffer->remark_begin(),
11190b57cec5SDimitry Andric                                    Buffer->remark_end(), "remark");
11200b57cec5SDimitry Andric     if (bool(DiagnosticLevelMask::Note & DiagMask))
11210b57cec5SDimitry Andric       NumErrors += PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
11220b57cec5SDimitry Andric                                    Buffer->note_end(), "note");
11230b57cec5SDimitry Andric   }
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric   Diags.setClient(CurClient, Owner.release() != nullptr);
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric   // Reset the buffer, we have processed all the diagnostics in it.
11280b57cec5SDimitry Andric   Buffer.reset(new TextDiagnosticBuffer());
11290b57cec5SDimitry Andric   ED.Reset();
11300b57cec5SDimitry Andric }
11310b57cec5SDimitry Andric 
11320b57cec5SDimitry Andric std::unique_ptr<Directive> Directive::create(bool RegexKind,
11330b57cec5SDimitry Andric                                              SourceLocation DirectiveLoc,
11340b57cec5SDimitry Andric                                              SourceLocation DiagnosticLoc,
11355ffd83dbSDimitry Andric                                              bool MatchAnyFileAndLine,
11360b57cec5SDimitry Andric                                              bool MatchAnyLine, StringRef Text,
11370b57cec5SDimitry Andric                                              unsigned Min, unsigned Max) {
11380b57cec5SDimitry Andric   if (!RegexKind)
1139a7dea167SDimitry Andric     return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
11405ffd83dbSDimitry Andric                                                MatchAnyFileAndLine,
11410b57cec5SDimitry Andric                                                MatchAnyLine, Text, Min, Max);
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric   // Parse the directive into a regular expression.
11440b57cec5SDimitry Andric   std::string RegexStr;
11450b57cec5SDimitry Andric   StringRef S = Text;
11460b57cec5SDimitry Andric   while (!S.empty()) {
1147*647cbc5dSDimitry Andric     if (S.consume_front("{{")) {
11480b57cec5SDimitry Andric       size_t RegexMatchLength = S.find("}}");
11490b57cec5SDimitry Andric       assert(RegexMatchLength != StringRef::npos);
11500b57cec5SDimitry Andric       // Append the regex, enclosed in parentheses.
11510b57cec5SDimitry Andric       RegexStr += "(";
11520b57cec5SDimitry Andric       RegexStr.append(S.data(), RegexMatchLength);
11530b57cec5SDimitry Andric       RegexStr += ")";
11540b57cec5SDimitry Andric       S = S.drop_front(RegexMatchLength + 2);
11550b57cec5SDimitry Andric     } else {
11560b57cec5SDimitry Andric       size_t VerbatimMatchLength = S.find("{{");
11570b57cec5SDimitry Andric       if (VerbatimMatchLength == StringRef::npos)
11580b57cec5SDimitry Andric         VerbatimMatchLength = S.size();
11590b57cec5SDimitry Andric       // Escape and append the fixed string.
11600b57cec5SDimitry Andric       RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
11610b57cec5SDimitry Andric       S = S.drop_front(VerbatimMatchLength);
11620b57cec5SDimitry Andric     }
11630b57cec5SDimitry Andric   }
11640b57cec5SDimitry Andric 
11655ffd83dbSDimitry Andric   return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc,
11665ffd83dbSDimitry Andric                                           MatchAnyFileAndLine, MatchAnyLine,
11675ffd83dbSDimitry Andric                                           Text, Min, Max, RegexStr);
11680b57cec5SDimitry Andric }
1169