[clang][VerifyDiagnosticConsumer] Support filename wildcards

Differential Revision: https://reviews.llvm.org/D72100
This commit is contained in:
Alexandre Rames 2020-05-14 15:09:30 -07:00 committed by Jan Korous
parent 0363ae97ab
commit 05eedf1f5b
4 changed files with 81 additions and 43 deletions

View File

@ -190,11 +190,10 @@ public:
/// ///
class Directive { class Directive {
public: public:
static std::unique_ptr<Directive> create(bool RegexKind, static std::unique_ptr<Directive>
SourceLocation DirectiveLoc, create(bool RegexKind, SourceLocation DirectiveLoc,
SourceLocation DiagnosticLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine,
bool MatchAnyLine, StringRef Text, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max);
unsigned Min, unsigned Max);
public: public:
/// Constant representing n or more matches. /// Constant representing n or more matches.
@ -205,6 +204,7 @@ public:
const std::string Text; const std::string Text;
unsigned Min, Max; unsigned Min, Max;
bool MatchAnyLine; bool MatchAnyLine;
bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
Directive(const Directive &) = delete; Directive(const Directive &) = delete;
Directive &operator=(const Directive &) = delete; Directive &operator=(const Directive &) = delete;
@ -219,9 +219,11 @@ public:
protected: protected:
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max) bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
: DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), unsigned Min, unsigned Max)
Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text),
Min(Min), Max(Max), MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
MatchAnyFileAndLine(MatchAnyFileAndLine) {
assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) && assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
"DiagnosticLoc is invalid!"); "DiagnosticLoc is invalid!");

View File

@ -89,9 +89,10 @@ namespace {
class StandardDirective : public Directive { class StandardDirective : public Directive {
public: public:
StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
bool MatchAnyLine, StringRef Text, unsigned Min, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
unsigned Max) unsigned Min, unsigned Max)
: Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) {} : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
MatchAnyLine, Text, Min, Max) {}
bool isValid(std::string &Error) override { bool isValid(std::string &Error) override {
// all strings are considered valid; even empty ones // all strings are considered valid; even empty ones
@ -107,9 +108,10 @@ public:
class RegexDirective : public Directive { class RegexDirective : public Directive {
public: public:
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
StringRef RegexStr) unsigned Min, unsigned Max, StringRef RegexStr)
: Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max), : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
MatchAnyLine, Text, Min, Max),
Regex(RegexStr) {} Regex(RegexStr) {}
bool isValid(std::string &Error) override { bool isValid(std::string &Error) override {
@ -294,11 +296,13 @@ struct UnattachedDirective {
// Attach the specified directive to the line of code indicated by // Attach the specified directive to the line of code indicated by
// \p ExpectedLoc. // \p ExpectedLoc.
void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD, void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
SourceLocation ExpectedLoc, bool MatchAnyLine = false) { SourceLocation ExpectedLoc,
bool MatchAnyFileAndLine = false,
bool MatchAnyLine = false) {
// Construct new directive. // Construct new directive.
std::unique_ptr<Directive> D = std::unique_ptr<Directive> D = Directive::create(
Directive::create(UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.RegexKind, UD.DirectivePos, ExpectedLoc, MatchAnyFileAndLine,
MatchAnyLine, UD.Text, UD.Min, UD.Max); MatchAnyLine, UD.Text, UD.Min, UD.Max);
std::string Error; std::string Error;
if (!D->isValid(Error)) { if (!D->isValid(Error)) {
@ -498,6 +502,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Next optional token: @ // Next optional token: @
SourceLocation ExpectedLoc; SourceLocation ExpectedLoc;
StringRef Marker; StringRef Marker;
bool MatchAnyFileAndLine = false;
bool MatchAnyLine = false; bool MatchAnyLine = false;
if (!PH.Next("@")) { if (!PH.Next("@")) {
ExpectedLoc = Pos; ExpectedLoc = Pos;
@ -526,26 +531,39 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
StringRef Filename(PH.C, PH.P-PH.C); StringRef Filename(PH.C, PH.P-PH.C);
PH.Advance(); PH.Advance();
// Lookup file via Preprocessor, like a #include. if (Filename == "*") {
const DirectoryLookup *CurDir; MatchAnyFileAndLine = true;
Optional<FileEntryRef> File = if (!PH.Next("*")) {
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
nullptr, nullptr, nullptr, nullptr, nullptr); diag::err_verify_missing_line)
if (!File) { << "'*'";
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), continue;
diag::err_verify_missing_file) << Filename << KindStr; }
continue;
}
const FileEntry *FE = &File->getFileEntry();
if (SM.translateFile(FE).isInvalid())
SM.createFileID(FE, Pos, SrcMgr::C_User);
if (PH.Next(Line) && Line > 0)
ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
else if (PH.Next("*")) {
MatchAnyLine = true; MatchAnyLine = true;
ExpectedLoc = SM.translateFileLineCol(FE, 1, 1); ExpectedLoc = SourceLocation();
} else {
// Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir;
Optional<FileEntryRef> File =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
diag::err_verify_missing_file)
<< Filename << KindStr;
continue;
}
const FileEntry *FE = &File->getFileEntry();
if (SM.translateFile(FE).isInvalid())
SM.createFileID(FE, Pos, SrcMgr::C_User);
if (PH.Next(Line) && Line > 0)
ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
else if (PH.Next("*")) {
MatchAnyLine = true;
ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
}
} }
} else if (PH.Next("*")) { } else if (PH.Next("*")) {
MatchAnyLine = true; MatchAnyLine = true;
@ -631,7 +649,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
} }
if (Marker.empty()) if (Marker.empty())
attachDirective(Diags, D, ExpectedLoc, MatchAnyLine); attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
else else
Markers.addDirective(Marker, D); Markers.addDirective(Marker, D);
FoundDirective = true; FoundDirective = true;
@ -877,7 +895,7 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags,
SmallString<256> Fmt; SmallString<256> Fmt;
llvm::raw_svector_ostream OS(Fmt); llvm::raw_svector_ostream OS(Fmt);
for (const auto *D : DL) { for (const auto *D : DL) {
if (D->DiagnosticLoc.isInvalid()) if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
OS << "\n File *"; OS << "\n File *";
else else
OS << "\n File " << SourceMgr.getFilename(D->DiagnosticLoc); OS << "\n File " << SourceMgr.getFilename(D->DiagnosticLoc);
@ -937,7 +955,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
continue; continue;
} }
if (!D.DiagnosticLoc.isInvalid() && if (!D.DiagnosticLoc.isInvalid() && !D.MatchAnyFileAndLine &&
!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
continue; continue;
@ -1114,11 +1132,13 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
std::unique_ptr<Directive> Directive::create(bool RegexKind, std::unique_ptr<Directive> Directive::create(bool RegexKind,
SourceLocation DirectiveLoc, SourceLocation DirectiveLoc,
SourceLocation DiagnosticLoc, SourceLocation DiagnosticLoc,
bool MatchAnyFileAndLine,
bool MatchAnyLine, StringRef Text, bool MatchAnyLine, StringRef Text,
unsigned Min, unsigned Max) { unsigned Min, unsigned Max) {
if (!RegexKind) if (!RegexKind)
return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc, return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
MatchAnyLine, Text, Min, Max); MatchAnyFileAndLine,
MatchAnyLine, Text, Min, Max);
// Parse the directive into a regular expression. // Parse the directive into a regular expression.
std::string RegexStr; std::string RegexStr;
@ -1143,6 +1163,7 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
} }
} }
return std::make_unique<RegexDirective>( return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc,
DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr); MatchAnyFileAndLine, MatchAnyLine,
Text, Min, Max, RegexStr);
} }

View File

@ -0,0 +1,14 @@
// RUN: not %clang_cc1 -verify %s 2>&1 | FileCheck %s
#include "verify-any-file.h"
// expected-error@*:* {{unknown type name 'unexpected'}}
// expected-error@*:* {{missing error}}
// expected-error@*:123 {{invalid line : "*" required}}
//
// CHECK: error: 'error' diagnostics expected but not seen:
// CHECK-NEXT: File * Line * (directive at {{.*}}verify-any-file.c:6): missing error
// CHECK-NEXT: error: 'error' diagnostics seen but not expected:
// CHECK-NEXT: File {{.*}}verify-any-file.c Line 8: missing or invalid line number following '@' in expected '*'
// CHECK-NEXT: 2 errors generated.

View File

@ -0,0 +1 @@
unexpected var;