diff options
author | David Blaikie <dblaikie@gmail.com> | 2011-09-26 00:38:03 +0000 |
---|---|---|
committer | David Blaikie <dblaikie@gmail.com> | 2011-09-26 00:38:03 +0000 |
commit | 621bc69624599da62abd9bc9e5edd8a63ac99fe6 (patch) | |
tree | 30d8135daf2b511a9d2be5499c2399f2d23401dc /lib/Frontend/VerifyDiagnosticsClient.cpp | |
parent | 761457827001290ca96bd2d5b05f182d21f28296 (diff) |
Rename VerifyDiagnosticsClient to VerifyDiagnosticConsumer as per issue 5397
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140489 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend/VerifyDiagnosticsClient.cpp')
-rw-r--r-- | lib/Frontend/VerifyDiagnosticsClient.cpp | 533 |
1 files changed, 0 insertions, 533 deletions
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp deleted file mode 100644 index c3a236fad4..0000000000 --- a/lib/Frontend/VerifyDiagnosticsClient.cpp +++ /dev/null @@ -1,533 +0,0 @@ -//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a concrete diagnostic client, which buffers the diagnostic messages. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/VerifyDiagnosticsClient.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Regex.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -VerifyDiagnosticsClient::VerifyDiagnosticsClient(DiagnosticsEngine &_Diags) - : Diags(_Diags), PrimaryClient(Diags.getClient()), - OwnsPrimaryClient(Diags.ownsClient()), - Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) -{ - Diags.takeClient(); -} - -VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { - CheckDiagnostics(); - Diags.takeClient(); - if (OwnsPrimaryClient) - delete PrimaryClient; -} - -// DiagnosticConsumer interface. - -void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP) { - // FIXME: Const hack, we screw up the preprocessor but in practice its ok - // because it doesn't get reused. It would be better if we could make a copy - // though. - CurrentPreprocessor = const_cast<Preprocessor*>(PP); - - PrimaryClient->BeginSourceFile(LangOpts, PP); -} - -void VerifyDiagnosticsClient::EndSourceFile() { - CheckDiagnostics(); - - PrimaryClient->EndSourceFile(); - - CurrentPreprocessor = 0; -} - -void VerifyDiagnosticsClient::HandleDiagnostic( - DiagnosticsEngine::Level DiagLevel, const DiagnosticInfo &Info) { - if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { - const SourceManager &SM = Info.getSourceManager(); - FirstErrorFID = SM.getFileID(Info.getLocation()); - } - // Send the diagnostic to the buffer, we will check it once we reach the end - // of the source file (or are destructed). - Buffer->HandleDiagnostic(DiagLevel, Info); -} - -//===----------------------------------------------------------------------===// -// Checking diagnostics implementation. -//===----------------------------------------------------------------------===// - -typedef TextDiagnosticBuffer::DiagList DiagList; -typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; - -namespace { - -/// Directive - Abstract class representing a parsed verify directive. -/// -class Directive { -public: - static Directive* Create(bool RegexKind, const SourceLocation &Location, - const std::string &Text, unsigned Count); -public: - SourceLocation Location; - const std::string Text; - unsigned Count; - - virtual ~Directive() { } - - // Returns true if directive text is valid. - // Otherwise returns false and populates E. - virtual bool isValid(std::string &Error) = 0; - - // Returns true on match. - virtual bool Match(const std::string &S) = 0; - -protected: - Directive(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Location(Location), Text(Text), Count(Count) { } - -private: - Directive(const Directive&); // DO NOT IMPLEMENT - void operator=(const Directive&); // DO NOT IMPLEMENT -}; - -/// StandardDirective - Directive with string matching. -/// -class StandardDirective : public Directive { -public: - StandardDirective(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Directive(Location, Text, Count) { } - - virtual bool isValid(std::string &Error) { - // all strings are considered valid; even empty ones - return true; - } - - virtual bool Match(const std::string &S) { - return S.find(Text) != std::string::npos || - Text.find(S) != std::string::npos; - } -}; - -/// RegexDirective - Directive with regular-expression matching. -/// -class RegexDirective : public Directive { -public: - RegexDirective(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Directive(Location, Text, Count), Regex(Text) { } - - virtual bool isValid(std::string &Error) { - if (Regex.isValid(Error)) - return true; - return false; - } - - virtual bool Match(const std::string &S) { - return Regex.match(S); - } - -private: - llvm::Regex Regex; -}; - -typedef std::vector<Directive*> DirectiveList; - -/// ExpectedData - owns directive objects and deletes on destructor. -/// -struct ExpectedData { - DirectiveList Errors; - DirectiveList Warnings; - DirectiveList Notes; - - ~ExpectedData() { - DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; - for (DirectiveList **PL = Lists; *PL; ++PL) { - DirectiveList * const L = *PL; - for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) - delete *I; - } - } -}; - -class ParseHelper -{ -public: - ParseHelper(const char *Begin, const char *End) - : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } - - // Return true if string literal is next. - bool Next(StringRef S) { - P = C; - PEnd = C + S.size(); - if (PEnd > End) - return false; - return !memcmp(P, S.data(), S.size()); - } - - // Return true if number is next. - // Output N only if number is next. - bool Next(unsigned &N) { - unsigned TMP = 0; - P = C; - for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) { - TMP *= 10; - TMP += P[0] - '0'; - } - if (P == C) - return false; - PEnd = P; - N = TMP; - return true; - } - - // Return true if string literal is found. - // When true, P marks begin-position of S in content. - bool Search(StringRef S) { - P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.size(); - return P != End; - } - - // Advance 1-past previous next/search. - // Behavior is undefined if previous next/search failed. - bool Advance() { - C = PEnd; - return C < End; - } - - // Skip zero or more whitespace. - void SkipWhitespace() { - for (; C < End && isspace(*C); ++C) - ; - } - - // Return true if EOF reached. - bool Done() { - return !(C < End); - } - - const char * const Begin; // beginning of expected content - const char * const End; // end of expected content (1-past) - const char *C; // position of next char in content - const char *P; - -private: - const char *PEnd; // previous next/search subject end (1-past) -}; - -} // namespace anonymous - -/// ParseDirective - Go through the comment and see if it indicates expected -/// diagnostics. If so, then put them in the appropriate directive list. -/// -static void ParseDirective(const char *CommentStart, unsigned CommentLen, - ExpectedData &ED, Preprocessor &PP, - SourceLocation Pos) { - // A single comment may contain multiple directives. - for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { - // search for token: expected - if (!PH.Search("expected")) - break; - PH.Advance(); - - // next token: - - if (!PH.Next("-")) - continue; - PH.Advance(); - - // next token: { error | warning | note } - DirectiveList* DL = NULL; - if (PH.Next("error")) - DL = &ED.Errors; - else if (PH.Next("warning")) - DL = &ED.Warnings; - else if (PH.Next("note")) - DL = &ED.Notes; - else - continue; - PH.Advance(); - - // default directive kind - bool RegexKind = false; - const char* KindStr = "string"; - - // next optional token: - - if (PH.Next("-re")) { - PH.Advance(); - RegexKind = true; - KindStr = "regex"; - } - - // skip optional whitespace - PH.SkipWhitespace(); - - // next optional token: positive integer - unsigned Count = 1; - if (PH.Next(Count)) - PH.Advance(); - - // skip optional whitespace - PH.SkipWhitespace(); - - // next token: {{ - if (!PH.Next("{{")) { - PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), - diag::err_verify_missing_start) << KindStr; - continue; - } - PH.Advance(); - const char* const ContentBegin = PH.C; // mark content begin - - // search for token: }} - if (!PH.Search("}}")) { - PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), - diag::err_verify_missing_end) << KindStr; - continue; - } - const char* const ContentEnd = PH.P; // mark content end - PH.Advance(); - - // build directive text; convert \n to newlines - std::string Text; - StringRef NewlineStr = "\\n"; - StringRef Content(ContentBegin, ContentEnd-ContentBegin); - size_t CPos = 0; - size_t FPos; - while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { - Text += Content.substr(CPos, FPos-CPos); - Text += '\n'; - CPos = FPos + NewlineStr.size(); - } - if (Text.empty()) - Text.assign(ContentBegin, ContentEnd); - - // construct new directive - Directive *D = Directive::Create(RegexKind, Pos, Text, Count); - std::string Error; - if (D->isValid(Error)) - DL->push_back(D); - else { - PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), - diag::err_verify_invalid_content) - << KindStr << Error; - } - } -} - -/// FindExpectedDiags - Lex the main source file to find all of the -// expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { - // Create a raw lexer to pull all the comments out of FID. - if (FID.isInvalid()) - return; - - SourceManager& SM = PP.getSourceManager(); - // Create a lexer to lex all the tokens of the main file in raw mode. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); - - // Return comments as tokens, this is how we find expected diagnostics. - RawLex.SetCommentRetentionState(true); - - Token Tok; - Tok.setKind(tok::comment); - while (Tok.isNot(tok::eof)) { - RawLex.Lex(Tok); - if (!Tok.is(tok::comment)) continue; - - std::string Comment = PP.getSpelling(Tok); - if (Comment.empty()) continue; - - // Find all expected errors/warnings/notes. - ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); - }; -} - -/// PrintProblem - This takes a diagnostic map of the delta between expected and -/// seen diagnostics. If there's anything in it, then something unexpected -/// happened. Print the map out in a nice format and return "true". If the map -/// is empty and we're not going to print things, then return "false". -/// -static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, - const_diag_iterator diag_begin, - const_diag_iterator diag_end, - const char *Kind, bool Expected) { - if (diag_begin == diag_end) return 0; - - llvm::SmallString<256> Fmt; - llvm::raw_svector_ostream OS(Fmt); - for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { - if (I->first.isInvalid() || !SourceMgr) - OS << "\n (frontend)"; - else - OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first); - OS << ": " << I->second; - } - - Diags.Report(diag::err_verify_inconsistent_diags) - << Kind << !Expected << OS.str(); - return std::distance(diag_begin, diag_end); -} - -static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, - DirectiveList &DL, const char *Kind, - bool Expected) { - if (DL.empty()) - return 0; - - llvm::SmallString<256> Fmt; - llvm::raw_svector_ostream OS(Fmt); - for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { - Directive& D = **I; - if (D.Location.isInvalid() || !SourceMgr) - OS << "\n (frontend)"; - else - OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location); - OS << ": " << D.Text; - } - - Diags.Report(diag::err_verify_inconsistent_diags) - << Kind << !Expected << OS.str(); - return DL.size(); -} - -/// CheckLists - Compare expected to seen diagnostic lists and return the -/// the difference between them. -/// -static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, - const char *Label, - DirectiveList &Left, - const_diag_iterator d2_begin, - const_diag_iterator d2_end) { - DirectiveList LeftOnly; - DiagList Right(d2_begin, d2_end); - - for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { - Directive& D = **I; - unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location); - - for (unsigned i = 0; i < D.Count; ++i) { - DiagList::iterator II, IE; - for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { - unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); - if (LineNo1 != LineNo2) - continue; - - const std::string &RightText = II->second; - if (D.Match(RightText)) - break; - } - if (II == IE) { - // Not found. - LeftOnly.push_back(*I); - } else { - // Found. The same cannot be found twice. - Right.erase(II); - } - } - } - // Now all that's left in Right are those that were not matched. - - return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) + - PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), - Label, false)); -} - -/// CheckResults - This compares the expected results to those that -/// were actually reported. It emits any discrepencies. Return "true" if there -/// were problems. Return "false" otherwise. -/// -static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, - const TextDiagnosticBuffer &Buffer, - ExpectedData &ED) { - // We want to capture the delta between what was expected and what was - // seen. - // - // Expected \ Seen - set expected but not seen - // Seen \ Expected - set seen but not expected - unsigned NumProblems = 0; - - // See if there are error mismatches. - NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors, - Buffer.err_begin(), Buffer.err_end()); - - // See if there are warning mismatches. - NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings, - Buffer.warn_begin(), Buffer.warn_end()); - - // See if there are note mismatches. - NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes, - Buffer.note_begin(), Buffer.note_end()); - - return NumProblems; -} - -void VerifyDiagnosticsClient::CheckDiagnostics() { - ExpectedData ED; - - // Ensure any diagnostics go to the primary client. - bool OwnsCurClient = Diags.ownsClient(); - DiagnosticConsumer *CurClient = Diags.takeClient(); - Diags.setClient(PrimaryClient, false); - - // If we have a preprocessor, scan the source for expected diagnostic - // markers. If not then any diagnostics are unexpected. - if (CurrentPreprocessor) { - SourceManager &SM = CurrentPreprocessor->getSourceManager(); - // Extract expected-error strings from main file. - FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); - // Only check for expectations in other diagnostic locations - // if they are not the main file (via ID or FileEntry) - the main - // file has already been looked at, and its expectations must not - // be added twice. - if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() - && (!SM.getFileEntryForID(FirstErrorFID) - || (SM.getFileEntryForID(FirstErrorFID) != - SM.getFileEntryForID(SM.getMainFileID())))) { - FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); - FirstErrorFID = FileID(); - } - - // Check that the expected diagnostics occurred. - NumErrors += CheckResults(Diags, SM, *Buffer, ED); - } else { - NumErrors += (PrintProblem(Diags, 0, - Buffer->err_begin(), Buffer->err_end(), - "error", false) + - PrintProblem(Diags, 0, - Buffer->warn_begin(), Buffer->warn_end(), - "warn", false) + - PrintProblem(Diags, 0, - Buffer->note_begin(), Buffer->note_end(), - "note", false)); - } - - Diags.takeClient(); - Diags.setClient(CurClient, OwnsCurClient); - - // Reset the buffer, we have processed all the diagnostics in it. - Buffer.reset(new TextDiagnosticBuffer()); -} - -Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, - const std::string &Text, unsigned Count) { - if (RegexKind) - return new RegexDirective(Location, Text, Count); - return new StandardDirective(Location, Text, Count); -} |