diff options
Diffstat (limited to 'lib/Frontend/VerifyDiagnosticConsumer.cpp')
-rw-r--r-- | lib/Frontend/VerifyDiagnosticConsumer.cpp | 143 |
1 files changed, 100 insertions, 43 deletions
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 427d15ed703a..0df5393a309b 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/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; @@ -416,9 +466,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, MatchAnyLine = true; ExpectedLoc = SM.translateFileLineCol(FE, 1, 1); } + } else if (PH.Next("*")) { + MatchAnyLine = true; + ExpectedLoc = SourceLocation(); } - if (ExpectedLoc.isInvalid()) { + if (ExpectedLoc.isInvalid() && !MatchAnyLine) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_line) << KindStr; continue; @@ -650,7 +703,10 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, llvm::raw_svector_ostream OS(Fmt); for (auto *DirPtr : DL) { Directive &D = *DirPtr; - OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc); + if (D.DiagnosticLoc.isInvalid()) + OS << "\n File *"; + else + OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc); if (D.MatchAnyLine) OS << " Line *"; else @@ -708,7 +764,8 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, continue; } - if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) + if (!D.DiagnosticLoc.isInvalid() && + !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) continue; const std::string &RightText = II->second; |