[cfe-commits] [PATCH] Support for [[@LINE]], [[@LINE+<offset>]], [[@LINE-<offset>]] expressions in FileCheck

Alexander Kornienko alexfh at google.com
Thu Nov 8 15:03:58 PST 2012


alexfh added you to the CC list for the revision "Support for [[@LINE]], [[@LINE+<offset>]], [[@LINE-<offset>]] expressions in FileCheck".

Hi chandlerc, gribozavr, doug.gregor,

Added support for [[@LINE]], [[@LINE+<offset>]], [[@LINE-<offset>]] expressions in FileCheck CHECK: lines.

This will help make many tests that rely on file line numbers less fragile. See tools/clang/test/Index/annotate-comments.cpp or tools/clang/test/Misc/caret-diags-macros.c, for a couple of examples.

http://llvm-reviews.chandlerc.com/D109

Files:
  utils/FileCheck/FileCheck.cpp

Index: utils/FileCheck/FileCheck.cpp
===================================================================
--- utils/FileCheck/FileCheck.cpp
+++ utils/FileCheck/FileCheck.cpp
@@ -26,6 +26,7 @@
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/system_error.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include <algorithm>
 using namespace llvm;
@@ -63,6 +64,9 @@
   /// RegEx - If non-empty, this is a regex pattern.
   std::string RegExStr;
 
+  /// \brief Contains the number of line this pattern is in.
+  int LineNumber;
+
   /// VariableUses - Entries in this vector map to uses of a variable in the
   /// pattern, e.g. "foo[[bar]]baz".  In this case, the RegExStr will contain
   /// "foobaz" and we'll get an entry in this vector that tells us to insert the
@@ -79,7 +83,7 @@
 
   Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
 
-  bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
+  bool ParsePattern(StringRef PatternStr, SourceMgr &SM, int LineNumber);
 
   /// Match - Match the pattern string against the input buffer Buffer.  This
   /// returns the position that is matched or npos if there is no match.  If
@@ -104,10 +108,14 @@
   /// should correspond to a perfect match.
   unsigned ComputeMatchDistance(StringRef Buffer,
                                const StringMap<StringRef> &VariableTable) const;
+
+  bool EvaluateExpression(StringRef Expr, std::string &Value) const;
 };
 
 
-bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
+bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
+                           int LineNumber) {
+  this->LineNumber = LineNumber;
   PatternLoc = SMLoc::getFromPointer(PatternStr.data());
 
   // Ignore trailing whitespace.
@@ -194,12 +202,19 @@
       }
 
       // Verify that the name is well formed.
-      for (unsigned i = 0, e = Name.size(); i != e; ++i)
-        if (Name[i] != '_' && !isalnum(Name[i])) {
+      bool IsExpression = false;
+      for (unsigned i = 0, e = Name.size(); i != e; ++i) {
+        if (i == 0 && Name[i] == '@') {
+          IsExpression = true;
+          continue;
+        }
+        if (Name[i] != '_' && !isalnum(Name[i]) &&
+            (!IsExpression || (Name[i] != '+' && Name[i] != '-'))) {
           SM.PrintMessage(SMLoc::getFromPointer(Name.data()+i),
                           SourceMgr::DK_Error, "invalid name in named regex");
           return true;
         }
+      }
 
       // Name can't start with a digit.
       if (isdigit(Name[0])) {
@@ -279,6 +294,24 @@
   return false;
 }
 
+bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const {
+  // The only supported expression is @LINE([\+-]\d+)?
+  if (!Expr.startswith("@LINE"))
+    return false;
+  Expr = Expr.substr(StringRef("@LINE").size());
+  int Offset = 0;
+  if (!Expr.empty()) {
+    if (Expr[0] == '+')
+      Expr = Expr.substr(1);
+    else if (Expr[0] != '-')
+      return false;
+    if (Expr.getAsInteger(10, Offset))
+      return false;
+  }
+  Value = llvm::itostr(LineNumber + Offset);
+  return true;
+}
+
 /// Match - Match the pattern string against the input buffer Buffer.  This
 /// returns the position that is matched or npos if there is no match.  If
 /// there is a match, the size of the matched string is returned in MatchLen.
@@ -307,15 +340,21 @@
 
     unsigned InsertOffset = 0;
     for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
-      StringMap<StringRef>::iterator it =
-        VariableTable.find(VariableUses[i].first);
-      // If the variable is undefined, return an error.
-      if (it == VariableTable.end())
-        return StringRef::npos;
-
-      // Look up the value and escape it so that we can plop it into the regex.
       std::string Value;
-      AddFixedStringToRegEx(it->second, Value);
+
+      if (VariableUses[i].first[0] == '@') {
+        if (!EvaluateExpression(VariableUses[i].first, Value))
+          return StringRef::npos;
+      } else {
+        StringMap<StringRef>::iterator it =
+          VariableTable.find(VariableUses[i].first);
+        // If the variable is undefined, return an error.
+        if (it == VariableTable.end())
+          return StringRef::npos;
+
+        // Look up the value and escape it so that we can plop it into the regex.
+        AddFixedStringToRegEx(it->second, Value);
+      }
 
       // Plop it into the regex at the adjusted offset.
       TmpStr.insert(TmpStr.begin()+VariableUses[i].second+InsertOffset,
@@ -371,19 +410,31 @@
   // variable values.
   if (!VariableUses.empty()) {
     for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
-      StringRef Var = VariableUses[i].first;
-      StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
       SmallString<256> Msg;
       raw_svector_ostream OS(Msg);
-
-      // Check for undefined variable references.
-      if (it == VariableTable.end()) {
-        OS << "uses undefined variable \"";
-        OS.write_escaped(Var) << "\"";;
+      StringRef Var = VariableUses[i].first;
+      if (Var[0] == '@') {
+        std::string Value;
+        if (EvaluateExpression(Var, Value)) {
+          OS << "with expression \"";
+          OS.write_escaped(Var) << "\" equal to \"";
+          OS.write_escaped(Value) << "\"";
+        } else {
+          OS << "uses incorrect expression \"";
+          OS.write_escaped(Var) << "\"";
+        }
       } else {
-        OS << "with variable \"";
-        OS.write_escaped(Var) << "\" equal to \"";
-        OS.write_escaped(it->second) << "\"";
+        StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
+
+        // Check for undefined variable references.
+        if (it == VariableTable.end()) {
+          OS << "uses undefined variable \"";
+          OS.write_escaped(Var) << "\"";
+        } else {
+          OS << "with variable \"";
+          OS.write_escaped(Var) << "\" equal to \"";
+          OS.write_escaped(it->second) << "\"";
+        }
       }
 
       SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
@@ -518,14 +569,20 @@
 
   std::vector<std::pair<SMLoc, Pattern> > NotMatches;
 
+  int LineNumber = 1;
+
   while (1) {
     // See if Prefix occurs in the memory buffer.
-    Buffer = Buffer.substr(Buffer.find(CheckPrefix));
-
+    size_t PrefixLoc = Buffer.find(CheckPrefix);
     // If we didn't find a match, we're done.
-    if (Buffer.empty())
+    if (PrefixLoc == StringRef::npos)
       break;
 
+    // Recalculate line number.
+    LineNumber += Buffer.substr(0, PrefixLoc).count('\n');
+
+    Buffer = Buffer.substr(PrefixLoc);
+
     const char *CheckPrefixStart = Buffer.data();
 
     // When we find a check prefix, keep track of whether we find CHECK: or
@@ -560,7 +617,7 @@
 
     // Parse the pattern.
     Pattern P;
-    if (P.ParsePattern(Buffer.substr(0, EOL), SM))
+    if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
       return true;
 
     Buffer = Buffer.substr(EOL);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D109.1.patch
Type: text/x-patch
Size: 7036 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20121108/363b1f4d/attachment.bin>


More information about the cfe-commits mailing list