From c1f152ee6c5163cd19a4f695bbb4321da2a0149b Mon Sep 17 00:00:00 2001 From: Andy Gibbs Date: Thu, 10 Jul 2014 16:43:29 +0000 Subject: [PATCH] Provide -verify support to match "any" line for diagnostics in included files. Allow diagnostic checks that originate in included files to be matched without necessarily determining the line number that the diagnostic occurs on. The new syntax replaces the line number with '*'. This extension is limited to diagnostics in included files and may be used where the include file is not part of the test-suite itself. Expected uses are for diagnostics originating in system headers, or for users who use -verify in testing 3rd-party library code where the location of diagnostics in header files may change from revision to revision and their precise location is not important to the success of the test-case. llvm-svn: 212735 --- .../clang/Frontend/VerifyDiagnosticConsumer.h | 12 ++++-- clang/lib/Frontend/VerifyDiagnosticConsumer.cpp | 45 ++++++++++++++-------- clang/test/Frontend/verify.c | 11 +++++- clang/test/Frontend/verify2.c | 21 +++++++++- clang/test/Frontend/verify2.h | 4 +- 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h index 084eb66..9273fac 100644 --- a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/clang/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/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 856b51d..b50950e 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/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 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/clang/test/Frontend/verify.c b/clang/test/Frontend/verify.c index 4bd0c90..e2e7894 100644 --- a/clang/test/Frontend/verify.c +++ b/clang/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/clang/test/Frontend/verify2.c b/clang/test/Frontend/verify2.c index 73eda4d..075a2ab 100644 --- a/clang/test/Frontend/verify2.c +++ b/clang/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/clang/test/Frontend/verify2.h b/clang/test/Frontend/verify2.h index 8acbf6e..a426722 100644 --- a/clang/test/Frontend/verify2.h +++ b/clang/test/Frontend/verify2.h @@ -1,5 +1,5 @@ -#error header - #if 0 // expected-error {{should be ignored}} #endif + +#error header -- 2.7.4