]> granicus.if.org Git - clang/commitdiff
Change VerifyDiagnosticConsumer so that it *must* contain at least one "expected...
authorAndy Gibbs <andyg1001@hotmail.co.uk>
Fri, 19 Oct 2012 12:49:32 +0000 (12:49 +0000)
committerAndy Gibbs <andyg1001@hotmail.co.uk>
Fri, 19 Oct 2012 12:49:32 +0000 (12:49 +0000)
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
include/clang/Basic/DiagnosticFrontendKinds.td
include/clang/Frontend/VerifyDiagnosticConsumer.h
lib/Frontend/VerifyDiagnosticConsumer.cpp
test/ARCMT/verify.m
test/Frontend/verify.c
test/Frontend/verify2.c
test/Frontend/verify3.c [new file with mode: 0644]

index 3f3e124ae64031eaf8b27f5d22b6e822ca2d9e79..57f06316b1b1055f2c12c73f2b2eac23525bf9e8 100644 (file)
@@ -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, <a
+href="/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details">here</a>.
 </p>
 
 <p>There are many other possible implementations of this interface, and this is
index 417a22c96df51a3ead45c6f107e5ade9a21abda2..c0099310cbace0d5ff95017beb9edca9c899d95a 100644 (file)
@@ -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<
index bf27eeea36b01be6628236275a8081b0987fe70e..06a3b24f3a3f434dfa0a2f5bccb3b85844f8e7ab 100644 (file)
@@ -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();
index 4f30d4213af9bfb569fa53c075e2e796f1cf6b14..1750946af497d9087f455cda237860f86ea6e5fc 100644 (file)
@@ -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 "\<EOL>" 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 {
index 9110fe6efae2dce45fc971ba6a337f4d8b5ddccb..bfb3b4b8ab55d7aa25dcec02cc82a4159e619bc4 100644 (file)
@@ -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.
index 8b4edc5a760e92b909b996e5eaa02dd5686e704a..062e6bd8618f924dd18ff0777640ece5c3cd92b3 100644 (file)
@@ -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
 
index a1c797581ed98f045bcc55384a7b99def8024e5a..04f80ad48e1a7c0dd8c653235b988dad383bedf3 100644 (file)
@@ -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 (file)
index 0000000..0705b4b
--- /dev/null
@@ -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