diff options
author | Hal Finkel <hfinkel@anl.gov> | 2017-12-16 02:23:22 +0000 |
---|---|---|
committer | Hal Finkel <hfinkel@anl.gov> | 2017-12-16 02:23:22 +0000 |
commit | 05e46484825f6d2f20d7738a728b1886f87b26fb (patch) | |
tree | 07ecc8800ec32bb3c0a6e11bcf508417dfd7b3a8 /clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | |
parent | fd563a0352cfe1a69afd7c6e280534bf141657ef (diff) | |
download | bcm5719-llvm-05e46484825f6d2f20d7738a728b1886f87b26fb.tar.gz bcm5719-llvm-05e46484825f6d2f20d7738a728b1886f87b26fb.zip |
[VerifyDiagnosticConsumer] support -verify=<prefixes>
This mimics FileCheck's --check-prefixes option.
The default prefix is "expected". That is, "-verify" is equivalent to
"-verify=expected".
The goal is to permit exercising a single test suite source file with different
compiler options producing different sets of diagnostics. While cpp can be
combined with the existing -verify to accomplish the same goal, source is often
easier to maintain when it's not cluttered with preprocessor directives or
duplicate passages of code. For example, this patch also rewrites some existing
clang tests to demonstrate the benefit of this feature.
Patch by Joel E. Denny, thanks!
Differential Revision: https://reviews.llvm.org/D39694
llvm-svn: 320908
Diffstat (limited to 'clang/lib/Frontend/VerifyDiagnosticConsumer.cpp')
-rw-r--r-- | clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 130 |
1 files changed, 90 insertions, 40 deletions
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index a49c424e915..0df5393a309 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -229,22 +229,52 @@ public: return true; } - // Return true if string literal is found. - // When true, P marks begin-position of S in content. - bool Search(StringRef S, bool EnsureStartOfWord = false) { + // Return true if string literal S is matched in content. + // When true, P marks begin-position of the match, and calling Advance sets C + // to end-position of the match. + // If S is the empty string, then search for any letter instead (makes sense + // with FinishDirectiveToken=true). + // If EnsureStartOfWord, then skip matches that don't start a new word. + // If FinishDirectiveToken, then assume the match is the start of a comment + // directive for -verify, and extend the match to include the entire first + // token of that directive. + bool Search(StringRef S, bool EnsureStartOfWord = false, + bool FinishDirectiveToken = false) { do { - P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.size(); + if (!S.empty()) { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.size(); + } + else { + P = C; + while (P != End && !isLetter(*P)) + ++P; + PEnd = P + 1; + } if (P == End) break; - if (!EnsureStartOfWord - // Check if string literal starts a new word. - || P == Begin || isWhitespace(P[-1]) - // Or it could be preceded by the start of a comment. - || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') - && P[-2] == '/')) - return true; - // Otherwise, skip and search again. + // If not start of word but required, skip and search again. + if (EnsureStartOfWord + // Check if string literal starts a new word. + && !(P == Begin || isWhitespace(P[-1]) + // Or it could be preceded by the start of a comment. + || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') + && P[-2] == '/'))) + continue; + if (FinishDirectiveToken) { + while (PEnd != End && (isAlphanumeric(*PEnd) + || *PEnd == '-' || *PEnd == '_')) + ++PEnd; + // Put back trailing digits and hyphens to be parsed later as a count + // or count range. Because -verify prefixes must start with letters, + // we know the actual directive we found starts with a letter, so + // we won't put back the entire directive word and thus record an empty + // string. + assert(isLetter(*P) && "-verify prefix must start with a letter"); + while (isDigit(PEnd[-1]) || PEnd[-1] == '-') + --PEnd; + } + return true; } while (Advance()); return false; } @@ -314,37 +344,68 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { - // Search for token: expected - if (!PH.Search("expected", true)) + // Search for the initial directive token. + // If one prefix, save time by searching only for its directives. + // Otherwise, search for any potential directive token and check it later. + const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes; + if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true) + : PH.Search("", true, true))) break; PH.Advance(); - // Next token: - - if (!PH.Next("-")) - continue; - PH.Advance(); + // Default directive kind. + bool RegexKind = false; + const char* KindStr = "string"; + + // Parse the initial directive token in reverse so we can easily determine + // its exact actual prefix. If we were to parse it from the front instead, + // it would be harder to determine where the prefix ends because there + // might be multiple matching -verify prefixes because some might prefix + // others. + StringRef DToken(PH.P, PH.C - PH.P); - // Next token: { error | warning | note } + // Regex in initial directive token: -re + if (DToken.endswith("-re")) { + RegexKind = true; + KindStr = "regex"; + DToken = DToken.substr(0, DToken.size()-3); + } + + // Type in initial directive token: -{error|warning|note|no-diagnostics} DirectiveList *DL = nullptr; - if (PH.Next("error")) + bool NoDiag = false; + StringRef DType; + if (DToken.endswith(DType="-error")) DL = ED ? &ED->Errors : nullptr; - else if (PH.Next("warning")) + else if (DToken.endswith(DType="-warning")) DL = ED ? &ED->Warnings : nullptr; - else if (PH.Next("remark")) + else if (DToken.endswith(DType="-remark")) DL = ED ? &ED->Remarks : nullptr; - else if (PH.Next("note")) + else if (DToken.endswith(DType="-note")) DL = ED ? &ED->Notes : nullptr; - else if (PH.Next("no-diagnostics")) { + else if (DToken.endswith(DType="-no-diagnostics")) { + NoDiag = true; + if (RegexKind) + continue; + } + else + continue; + DToken = DToken.substr(0, DToken.size()-DType.size()); + + // What's left in DToken is the actual prefix. That might not be a -verify + // prefix even if there is only one -verify prefix (for example, the full + // DToken is foo-bar-warning, but foo is the only -verify prefix). + if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken)) + continue; + + if (NoDiag) { if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/true; else Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; continue; - } else - continue; - PH.Advance(); - + } if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/false; @@ -357,17 +418,6 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, if (!DL) return true; - // Default directive kind. - bool RegexKind = false; - const char* KindStr = "string"; - - // Next optional token: - - if (PH.Next("-re")) { - PH.Advance(); - RegexKind = true; - KindStr = "regex"; - } - // Next optional token: @ SourceLocation ExpectedLoc; bool MatchAnyLine = false; |