From 266dba3661928d26f043560b169bea87578aa917 Mon Sep 17 00:00:00 2001 From: Andy Gibbs Date: Fri, 19 Oct 2012 12:49:32 +0000 Subject: [PATCH] Change VerifyDiagnosticConsumer so that it *must* contain at least one "expected-*" directive. As a result, for test-cases that are not expected to generate any diagnostics, an additional directive "expected-no-diagnostics" has been implemented which can then be included in such test-cases. This new directive may not be used in conjunction with any other "expected-*" directive. This change was initially proposed as a solution to the problem highlighted by check-in r164677, i.e. that -verify will not cause a test-case failure where the compile command does not actually reference the file. Patch reviewed by David Blaikie. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166281 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/InternalsManual.html | 4 +- .../clang/Basic/DiagnosticFrontendKinds.td | 5 +++ .../clang/Frontend/VerifyDiagnosticConsumer.h | 26 +++++++++++- lib/Frontend/VerifyDiagnosticConsumer.cpp | 37 ++++++++++++++--- test/ARCMT/verify.m | 5 ++- test/Frontend/verify.c | 5 ++- test/Frontend/verify2.c | 7 ++-- test/Frontend/verify3.c | 41 +++++++++++++++++++ 8 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 test/Frontend/verify3.c diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index 3f3e124ae6..57f06316b1 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -502,7 +502,9 @@ code, the source ranges, and the caret. However, this behavior isn't required. Instead of formatting and printing out the diagnostics, this implementation just captures and remembers the diagnostics as they fly by. Then -verify compares the list of produced diagnostics to the list of expected ones. If they disagree, -it prints out its own output. +it prints out its own output. Full documentation for the -verify mode can be +found in the Clang API documentation for VerifyDiagnosticConsumer, here.

There are many other possible implementations of this interface, and this is diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 417a22c96d..c0099310cb 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -76,6 +76,11 @@ def err_verify_invalid_content : Error< def err_verify_inconsistent_diags : Error< "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: " "%2">; +def err_verify_invalid_no_diags : Error< + "%select{expected|'expected-no-diagnostics'}0 directive cannot follow " + "%select{'expected-no-diagnostics' directive|other expected directives}0">; +def err_verify_no_directives : Error< + "no expected directives found: consider use of 'expected-no-diagnostics'">; def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; def note_fixit_in_macro : Note< diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h index bf27eeea36..06a3b24f3a 100644 --- a/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -33,7 +33,9 @@ class FileEntry; /// Indicating that a line expects an error or a warning is simple. Put a /// comment on the line that has the diagnostic, use: /// -/// expected-{error,warning,note} +/// \code +/// expected-{error,warning,note} +/// \endcode /// /// to tag if it's an expected error or warning, and place the expected text /// between {{ and }} markers. The full text doesn't have to be included, only @@ -94,12 +96,15 @@ class FileEntry; /// /// In this example, the diagnostic may appear only once, if at all. /// -/// Regex matching mode may be selected by appending '-re' to type. Example: +/// Regex matching mode may be selected by appending '-re' to type, such as: /// +/// \code /// expected-error-re +/// \endcode /// /// Examples matching error: "variable has incomplete type 'struct s'" /// +/// \code /// // expected-error {{variable has incomplete type 'struct s'}} /// // expected-error {{variable has incomplete type}} /// @@ -107,6 +112,15 @@ class FileEntry; /// // expected-error-re {{variable has has type 'struct .*'}} /// // expected-error-re {{variable has has type 'struct (.*)'}} /// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}} +/// \endcode +/// +/// VerifyDiagnosticConsumer expects at least one expected-* directive to +/// be found inside the source code. If no diagnostics are expected the +/// following directive can be used to indicate this: +/// +/// \code +/// // expected-no-diagnostics +/// \endcode /// class VerifyDiagnosticConsumer: public DiagnosticConsumer, public CommentHandler { @@ -166,6 +180,13 @@ public: } }; + enum DirectiveStatus { + HasNoDirectives, + HasNoDirectivesReported, + HasExpectedNoDiagnostics, + HasOtherExpectedDirectives + }; + private: DiagnosticsEngine &Diags; DiagnosticConsumer *PrimaryClient; @@ -175,6 +196,7 @@ private: const LangOptions *LangOpts; SourceManager *SrcManager; unsigned ActiveSourceFiles; + DirectiveStatus Status; ExpectedData ED; void CheckDiagnostics(); diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 4f30d4213a..1750946af4 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -31,7 +31,7 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) : Diags(_Diags), PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()), Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), - LangOpts(0), SrcManager(0), ActiveSourceFiles(0) + LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives) { Diags.takeClient(); if (Diags.hasSourceManager()) @@ -278,7 +278,8 @@ private: /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, - SourceLocation Pos, DiagnosticsEngine &Diags) { + SourceLocation Pos, DiagnosticsEngine &Diags, + VerifyDiagnosticConsumer::DirectiveStatus &Status) { // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { @@ -300,10 +301,24 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, DL = ED ? &ED->Warnings : NULL; else if (PH.Next("note")) DL = ED ? &ED->Notes : NULL; - else + else if (PH.Next("no-diagnostics")) { + 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; + continue; + } + Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives; + // If a directive has been found but we're not interested // in storing the directive information, return now. if (!DL) @@ -450,7 +465,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, // Fold any "\" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { - ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -480,7 +495,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, } if (!C2.empty()) - ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -505,6 +520,8 @@ static bool findDirectives(SourceManager &SM, FileID FID, Token Tok; Tok.setKind(tok::comment); + VerifyDiagnosticConsumer::DirectiveStatus Status = + VerifyDiagnosticConsumer::HasNoDirectives; while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; @@ -514,7 +531,7 @@ static bool findDirectives(SourceManager &SM, FileID FID, // Find first directive. if (ParseDirective(Comment, 0, SM, Tok.getLocation(), - SM.getDiagnostics())) + SM.getDiagnostics(), Status)) return true; } return false; @@ -718,6 +735,14 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { #endif // !NDEBUG if (SrcManager) { + // Produce an error if no expected-* directives could be found in the + // source file(s) processed. + if (Status == HasNoDirectives) { + Diags.Report(diag::err_verify_no_directives).setForceEmit(); + ++NumErrors; + Status = HasNoDirectivesReported; + } + // Check that the expected diagnostics occurred. NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED); } else { diff --git a/test/ARCMT/verify.m b/test/ARCMT/verify.m index 9110fe6efa..bfb3b4b8ab 100644 --- a/test/ARCMT/verify.m +++ b/test/ARCMT/verify.m @@ -8,6 +8,7 @@ #error should not be ignored // expected-error@-1 {{should not be ignored}} -// CHECK: error: 'error' diagnostics seen but not expected: +// CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics' +// CHECK-NEXT: error: 'error' diagnostics seen but not expected: // CHECK-NEXT: (frontend): error reading '{{.*}}verify.m.tmp.invalid' -// CHECK-NEXT: 1 error generated. +// CHECK-NEXT: 2 errors generated. diff --git a/test/Frontend/verify.c b/test/Frontend/verify.c index 8b4edc5a76..062e6bd861 100644 --- a/test/Frontend/verify.c +++ b/test/Frontend/verify.c @@ -111,9 +111,10 @@ unexpected b; // expected-error@33 1-1 {{unknown type}} #if 0 // RUN: %clang_cc1 -verify %t.invalid 2>&1 | FileCheck -check-prefix=CHECK6 %s -// CHECK6: error: 'error' diagnostics seen but not expected: +// CHECK6: error: no expected directives found: consider use of 'expected-no-diagnostics' +// CHECK6-NEXT: error: 'error' diagnostics seen but not expected: // CHECK6-NEXT: (frontend): error reading '{{.*}}verify.c.tmp.invalid' -// CHECK6-NEXT: 1 error generated. +// CHECK6-NEXT: 2 errors generated. // RUN: echo -e '//expected-error@2{{1}}\n#error 2' | %clang_cc1 -verify 2>&1 | FileCheck -check-prefix=CHECK7 %s diff --git a/test/Frontend/verify2.c b/test/Frontend/verify2.c index a1c797581e..04f80ad48e 100644 --- a/test/Frontend/verify2.c +++ b/test/Frontend/verify2.c @@ -3,7 +3,7 @@ // Please note that all comments are inside "#if 0" blocks so that // VerifyDiagnosticConsumer sees no comments while processing this -// test-case. +// test-case (and hence no expected-* directives). #endif #include "verify2.h" @@ -12,8 +12,9 @@ #if 0 // expected-error {{should be ignored}} -// CHECK: error: 'error' diagnostics seen but not expected: +// 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 10: source -// CHECK-NEXT: 2 errors generated. +// CHECK-NEXT: 3 errors generated. #endif diff --git a/test/Frontend/verify3.c b/test/Frontend/verify3.c new file mode 100644 index 0000000000..0705b4b7ee --- /dev/null +++ b/test/Frontend/verify3.c @@ -0,0 +1,41 @@ +// This test-case runs several sub-tests on -verify to ensure that correct +// diagnostics are generated in relation to the mis-use and non-use of the +// 'expected-no-diagnostics' directive. + +// RUN: %clang_cc1 -DTEST1 -verify %s 2>&1 | FileCheck -check-prefix=CHECK1 %s +#ifdef TEST1 +// expected-no-diagnostics +// expected-note {{}} + +// CHECK1: error: 'error' diagnostics seen but not expected: +// CHECK1-NEXT: Line 8: expected directive cannot follow 'expected-no-diagnostics' directive +// CHECK1-NEXT: 1 error generated. +#endif + +// RUN: %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s +#ifdef TEST2 +#warning X +// expected-warning@-1 {{X}} +// expected-no-diagnostics + +// CHECK2: error: 'error' diagnostics seen but not expected: +// CHECK2-NEXT: Line 19: 'expected-no-diagnostics' directive cannot follow other expected directives +// CHECK2-NEXT: 1 error generated. +#endif + +// RUN: %clang_cc1 -DTEST3 -verify %s 2>&1 | FileCheck -check-prefix=CHECK3 %s +// RUN: %clang_cc1 -verify 2>&1 | FileCheck -check-prefix=CHECK3 %s +#ifdef TEST3 +// no directives + +// CHECK3: error: no expected directives found: consider use of 'expected-no-diagnostics' +// CHECK3-NEXT: 1 error generated. +#endif + +// RUN: %clang_cc1 -E -DTEST4 -verify %s 2>&1 | FileCheck -check-prefix=CHECK4 %s +#ifdef TEST4 +#warning X +// expected-warning@-1 {{X}} + +// CHECK4-NOT: error: no expected directives found: consider use of 'expected-no-diagnostics' +#endif -- 2.40.0