forked from OSchip/llvm-project
[clang][VerifyDiagnosticConsumer] Support filename wildcards
Differential Revision: https://reviews.llvm.org/D72100
This commit is contained in:
parent
0363ae97ab
commit
05eedf1f5b
|
@ -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!");
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
||||||
|
unexpected var;
|
Loading…
Reference in New Issue