[clang][VerifyDiagnosticConsumer] Support filename wildcards
authorAlexandre Rames <arames@apple.com>
Thu, 14 May 2020 22:09:30 +0000 (15:09 -0700)
committerJan Korous <jkorous@apple.com>
Thu, 14 May 2020 22:15:49 +0000 (15:15 -0700)
Differential Revision: https://reviews.llvm.org/D72100

clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
clang/test/Frontend/verify-any-file.c [new file with mode: 0644]
clang/test/Frontend/verify-any-file.h [new file with mode: 0644]

index 7daebe6..a97cd13 100644 (file)
@@ -190,11 +190,10 @@ public:
   ///
   class Directive {
   public:
-    static std::unique_ptr<Directive> create(bool RegexKind,
-                                             SourceLocation DirectiveLoc,
-                                             SourceLocation DiagnosticLoc,
-                                             bool MatchAnyLine, StringRef Text,
-                                             unsigned Min, unsigned Max);
+    static std::unique_ptr<Directive>
+    create(bool RegexKind, SourceLocation DirectiveLoc,
+           SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine,
+           bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max);
 
   public:
     /// Constant representing n or more matches.
@@ -205,6 +204,7 @@ public:
     const std::string Text;
     unsigned Min, Max;
     bool MatchAnyLine;
+    bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
 
     Directive(const Directive &) = delete;
     Directive &operator=(const Directive &) = delete;
@@ -219,9 +219,11 @@ public:
 
   protected:
     Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
-              bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
-        : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
-          Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) {
+              bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
+              unsigned Min, unsigned Max)
+        : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text),
+          Min(Min), Max(Max), MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
+          MatchAnyFileAndLine(MatchAnyFileAndLine) {
       assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
       assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
              "DiagnosticLoc is invalid!");
index 82c2af8..56e0524 100644 (file)
@@ -89,9 +89,10 @@ namespace {
 class StandardDirective : public Directive {
 public:
   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
-                    bool MatchAnyLine, StringRef Text, unsigned Min,
-                    unsigned Max)
-      : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) {}
+                    bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
+                    unsigned Min, unsigned Max)
+      : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
+                  MatchAnyLine, Text, Min, Max) {}
 
   bool isValid(std::string &Error) override {
     // all strings are considered valid; even empty ones
@@ -107,9 +108,10 @@ public:
 class RegexDirective : public Directive {
 public:
   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
-                 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,
-                 StringRef RegexStr)
-      : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max),
+                 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
+                 unsigned Min, unsigned Max, StringRef RegexStr)
+      : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
+                  MatchAnyLine, Text, Min, Max),
         Regex(RegexStr) {}
 
   bool isValid(std::string &Error) override {
@@ -294,11 +296,13 @@ struct UnattachedDirective {
 // Attach the specified directive to the line of code indicated by
 // \p ExpectedLoc.
 void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
-                     SourceLocation ExpectedLoc, bool MatchAnyLine = false) {
+                     SourceLocation ExpectedLoc,
+                     bool MatchAnyFileAndLine = false,
+                     bool MatchAnyLine = false) {
   // Construct new directive.
-  std::unique_ptr<Directive> D =
-      Directive::create(UD.RegexKind, UD.DirectivePos, ExpectedLoc,
-                        MatchAnyLine, UD.Text, UD.Min, UD.Max);
+  std::unique_ptr<Directive> D = Directive::create(
+      UD.RegexKind, UD.DirectivePos, ExpectedLoc, MatchAnyFileAndLine,
+      MatchAnyLine, UD.Text, UD.Min, UD.Max);
 
   std::string Error;
   if (!D->isValid(Error)) {
@@ -498,6 +502,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
     // Next optional token: @
     SourceLocation ExpectedLoc;
     StringRef Marker;
+    bool MatchAnyFileAndLine = false;
     bool MatchAnyLine = false;
     if (!PH.Next("@")) {
       ExpectedLoc = Pos;
@@ -526,26 +531,39 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
         StringRef Filename(PH.C, PH.P-PH.C);
         PH.Advance();
 
-        // 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("*")) {
+        if (Filename == "*") {
+          MatchAnyFileAndLine = true;
+          if (!PH.Next("*")) {
+            Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                         diag::err_verify_missing_line)
+                << "'*'";
+            continue;
+          }
           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("*")) {
         MatchAnyLine = true;
@@ -631,7 +649,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
     }
 
     if (Marker.empty())
-      attachDirective(Diags, D, ExpectedLoc, MatchAnyLine);
+      attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
     else
       Markers.addDirective(Marker, D);
     FoundDirective = true;
@@ -877,7 +895,7 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags,
   SmallString<256> Fmt;
   llvm::raw_svector_ostream OS(Fmt);
   for (const auto *D : DL) {
-    if (D->DiagnosticLoc.isInvalid())
+    if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
       OS << "\n  File *";
     else
       OS << "\n  File " << SourceMgr.getFilename(D->DiagnosticLoc);
@@ -937,7 +955,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
             continue;
         }
 
-        if (!D.DiagnosticLoc.isInvalid() &&
+        if (!D.DiagnosticLoc.isInvalid() && !D.MatchAnyFileAndLine &&
             !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
           continue;
 
@@ -1114,11 +1132,13 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
 std::unique_ptr<Directive> Directive::create(bool RegexKind,
                                              SourceLocation DirectiveLoc,
                                              SourceLocation DiagnosticLoc,
+                                             bool MatchAnyFileAndLine,
                                              bool MatchAnyLine, StringRef Text,
                                              unsigned Min, unsigned Max) {
   if (!RegexKind)
     return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
-                                                MatchAnyLine, Text, Min, Max);
+                                               MatchAnyFileAndLine,
+                                               MatchAnyLine, Text, Min, Max);
 
   // Parse the directive into a regular expression.
   std::string RegexStr;
@@ -1143,6 +1163,7 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
     }
   }
 
-  return std::make_unique<RegexDirective>(
-      DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr);
+  return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc,
+                                          MatchAnyFileAndLine, MatchAnyLine,
+                                          Text, Min, Max, RegexStr);
 }
diff --git a/clang/test/Frontend/verify-any-file.c b/clang/test/Frontend/verify-any-file.c
new file mode 100644 (file)
index 0000000..d2c0d90
--- /dev/null
@@ -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.
diff --git a/clang/test/Frontend/verify-any-file.h b/clang/test/Frontend/verify-any-file.h
new file mode 100644 (file)
index 0000000..dee8fa3
--- /dev/null
@@ -0,0 +1 @@
+unexpected var;