diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h index 084eb66d859ead6d27573f368b27e66ee9f8395d..9273fac50910d739c9a4c82180741dda68fbedbe 100644 --- a/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -71,7 +71,10 @@ class FileEntry; /// \endcode /// /// The path can be absolute or relative and the same search paths will be used -/// as for #include directives. +/// as for #include directives. The line number in an external file may be +/// substituted with '*' meaning that any line number will match (useful where +/// the included file is, for example, a system header where the actual line +/// number may change and is not critical). /// /// The simple syntax above allows each specification to match exactly one /// error. You can use the extended syntax to customize this. The extended @@ -143,7 +146,7 @@ public: class Directive { public: static Directive *create(bool RegexKind, SourceLocation DirectiveLoc, - SourceLocation DiagnosticLoc, + SourceLocation DiagnosticLoc, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max); public: /// Constant representing n or more matches. @@ -153,6 +156,7 @@ public: SourceLocation DiagnosticLoc; const std::string Text; unsigned Min, Max; + bool MatchAnyLine; virtual ~Directive() { } @@ -165,9 +169,9 @@ public: protected: Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, - StringRef Text, unsigned Min, unsigned Max) + bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max) : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), - Text(Text), Min(Min), Max(Max) { + Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); } diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 856b51db3dcdc2861f6e0deb82cad47be58c076a..b50950e9b300b57eb81e6675493152acf2b51e49 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -164,8 +164,9 @@ namespace { class StandardDirective : public Directive { public: StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, - StringRef Text, unsigned Min, unsigned Max) - : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { } + bool MatchAnyLine, StringRef Text, unsigned Min, + unsigned Max) + : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) { } bool isValid(std::string &Error) override { // all strings are considered valid; even empty ones @@ -182,8 +183,10 @@ public: class RegexDirective : public Directive { public: RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, - StringRef Text, unsigned Min, unsigned Max, StringRef RegexStr) - : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(RegexStr) { } + bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max, + StringRef RegexStr) + : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max), + Regex(RegexStr) { } bool isValid(std::string &Error) override { if (Regex.isValid(Error)) @@ -371,6 +374,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // Next optional token: @ SourceLocation ExpectedLoc; + bool MatchAnyLine = false; if (!PH.Next("@")) { ExpectedLoc = Pos; } else { @@ -411,6 +415,10 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, if (PH.Next(Line) && Line > 0) ExpectedLoc = SM.translateFileLineCol(FE, Line, 1); + else if (PH.Next("*")) { + MatchAnyLine = true; + ExpectedLoc = SM.translateFileLineCol(FE, 1, 1); + } } if (ExpectedLoc.isInvalid()) { @@ -495,7 +503,8 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // Construct new directive. std::unique_ptr<Directive> D( - Directive::create(RegexKind, Pos, ExpectedLoc, Text, Min, Max)); + Directive::create(RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, + Min, Max)); std::string Error; if (D->isValid(Error)) { @@ -644,8 +653,11 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; - OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc) - << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); + OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc); + if (D.MatchAnyLine) + OS << " Line *"; + else + OS << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); if (D.DirectiveLoc != D.DiagnosticLoc) OS << " (directive at " << SourceMgr.getFilename(D.DirectiveLoc) << ':' @@ -692,9 +704,11 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, for (unsigned i = 0; i < D.Max; ++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; + if (!D.MatchAnyLine) { + unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); + if (LineNo1 != LineNo2) + continue; + } if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) continue; @@ -859,10 +873,11 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { } Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc, - SourceLocation DiagnosticLoc, StringRef Text, - unsigned Min, unsigned Max) { + SourceLocation DiagnosticLoc, bool MatchAnyLine, + StringRef Text, unsigned Min, unsigned Max) { if (!RegexKind) - return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max); + return new StandardDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine, + Text, Min, Max); // Parse the directive into a regular expression. std::string RegexStr; @@ -887,6 +902,6 @@ Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc, } } - return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max, - RegexStr); + return new RegexDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, + Min, Max, RegexStr); } diff --git a/test/Frontend/verify.c b/test/Frontend/verify.c index 4bd0c90b4aea3a3fa3beb081d3b76a2faae5b081..e2e7894f3b9ed41bcce076c953c7897e140fd19c 100644 --- a/test/Frontend/verify.c +++ b/test/Frontend/verify.c @@ -134,9 +134,18 @@ unexpected b; // expected-error@33 1-1 {{unknown type}} // expected-warning@verify-directive.h: {{ }} // expected-error@-1 {{missing or invalid line number}} +// expected-warning@verify-directive.h:0 {{ }} +// expected-error@-1 {{missing or invalid line number}} + +// expected-warning@verify-directive.h:0*{{ }} +// expected-error@-1 {{missing or invalid line number}} + +// expected-warning@verify-directive.h:*0{{ }} +// syntactically ok -- means match in any line for 0 occurrences. + // expected-warning@verify-directive.h:1 {{diagnostic}} // CHECK8: error: 'warning' diagnostics expected but not seen: -// CHECK8-NEXT: File {{.*}}verify-directive.h Line 1 (directive at {{.*}}verify.c:137): diagnostic +// CHECK8-NEXT: File {{.*}}verify-directive.h Line 1 (directive at {{.*}}verify.c:146): diagnostic // CHECK8-NEXT: 1 error generated. #endif diff --git a/test/Frontend/verify2.c b/test/Frontend/verify2.c index 73eda4d815de8a1ea5aa9dbbcacc05f23518bb41..075a2ab6e0f01ca3181ae40f11787b92f59c4acc 100644 --- a/test/Frontend/verify2.c +++ b/test/Frontend/verify2.c @@ -14,7 +14,26 @@ // CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' // CHECK-NEXT: error: 'error' diagnostics seen but not expected: -// CHECK-NEXT: Line 1: header +// CHECK-NEXT: Line 5: header // CHECK-NEXT: Line 10: source // CHECK-NEXT: 3 errors generated. #endif + +#ifdef CHECK2 +// RUN: not %clang_cc1 -DCHECK2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s + +// The following checks that -verify can match "any line" in an included file. +// The location of the diagnostic need therefore only match in the file, not to +// a specific line number. This is useful where -verify is used as a testing +// tool for 3rd-party libraries where headers may change and the specific line +// number of a diagnostic in a header is not important. + +// expected-error@verify2.h:* {{header}} +// expected-error@verify2.h:* {{unknown}} + +// CHECK2: error: 'error' diagnostics expected but not seen: +// CHECK2-NEXT: File {{.*}}verify2.h Line * (directive at {{.*}}verify2.c:32): unknown +// CHECK2-NEXT: error: 'error' diagnostics seen but not expected: +// CHECK2-NEXT: File {{.*}}verify2.c Line 10: source +// CHECK2-NEXT: 2 errors generated. +#endif diff --git a/test/Frontend/verify2.h b/test/Frontend/verify2.h index 8acbf6efdfe2c0812712faa95fefc9015710de98..a426722ee6e7a5856978ff68f30bb3f4643de0b6 100644 --- a/test/Frontend/verify2.h +++ b/test/Frontend/verify2.h @@ -1,5 +1,5 @@ -#error header - #if 0 // expected-error {{should be ignored}} #endif + +#error header