r305021 - [ASTMatchers] Add support for floatLiterals

Peter Wu via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 8 15:00:50 PDT 2017


Author: lekensteyn
Date: Thu Jun  8 17:00:50 2017
New Revision: 305021

URL: http://llvm.org/viewvc/llvm-project?rev=305021&view=rev
Log:
[ASTMatchers] Add support for floatLiterals

Summary:
Needed to support something like "floatLiteral(equals(1.0))". The
parser for floating point numbers is kept simple, so instead of ".1" you
have to use "0.1".

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D33135

Modified:
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Thu Jun  8 17:00:50 2017
@@ -76,7 +76,7 @@ public:
     ET_ParserInvalidToken = 106,
     ET_ParserMalformedBindExpr = 107,
     ET_ParserTrailingCode = 108,
-    ET_ParserUnsignedError = 109,
+    ET_ParserNumberError = 109,
     ET_ParserOverloadedType = 110
   };
 

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h Thu Jun  8 17:00:50 2017
@@ -19,9 +19,10 @@
 /// \code
 /// Grammar for the expressions supported:
 /// <Expression>        := <Literal> | <NamedValue> | <MatcherExpression>
-/// <Literal>           := <StringLiteral> | <Boolean> | <Unsigned>
+/// <Literal>           := <StringLiteral> | <Boolean> | <Double> | <Unsigned>
 /// <StringLiteral>     := "quoted string"
 /// <Boolean>           := true | false
+/// <Double>            := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+
 /// <Unsigned>          := [0-9]+
 /// <NamedValue>        := <Identifier>
 /// <MatcherExpression> := <Identifier>(<ArgumentList>) |

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Thu Jun  8 17:00:50 2017
@@ -36,6 +36,7 @@ class ArgKind {
   enum Kind {
     AK_Matcher,
     AK_Boolean,
+    AK_Double,
     AK_Unsigned,
     AK_String
   };
@@ -243,6 +244,7 @@ struct VariantMatcher::TypedMatcherOps f
 ///
 /// Supported types:
 ///  - \c bool
+//   - \c double
 ///  - \c unsigned
 ///  - \c llvm::StringRef
 ///  - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
@@ -256,6 +258,7 @@ public:
 
   /// \brief Specific constructors for each supported type.
   VariantValue(bool Boolean);
+  VariantValue(double Double);
   VariantValue(unsigned Unsigned);
   VariantValue(StringRef String);
   VariantValue(const VariantMatcher &Matchers);
@@ -272,6 +275,11 @@ public:
   bool getBoolean() const;
   void setBoolean(bool Boolean);
 
+  /// \brief Double value functions.
+  bool isDouble() const;
+  double getDouble() const;
+  void setDouble(double Double);
+
   /// \brief Unsigned value functions.
   bool isUnsigned() const;
   unsigned getUnsigned() const;
@@ -315,6 +323,7 @@ private:
   enum ValueType {
     VT_Nothing,
     VT_Boolean,
+    VT_Double,
     VT_Unsigned,
     VT_String,
     VT_Matcher
@@ -323,6 +332,7 @@ private:
   /// \brief All supported value types.
   union AllValues {
     unsigned Unsigned;
+    double Double;
     bool Boolean;
     std::string *String;
     VariantMatcher *Matcher;

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Thu Jun  8 17:00:50 2017
@@ -118,8 +118,8 @@ static StringRef errorTypeToFormatString
     return "Malformed bind() expression.";
   case Diagnostics::ET_ParserTrailingCode:
     return "Expected end of code.";
-  case Diagnostics::ET_ParserUnsignedError:
-    return "Error parsing unsigned token: <$0>";
+  case Diagnostics::ET_ParserNumberError:
+    return "Error parsing numeric literal: <$0>";
   case Diagnostics::ET_ParserOverloadedType:
     return "Input value has unresolved overloaded type: $0";
 

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Thu Jun  8 17:00:50 2017
@@ -75,6 +75,16 @@ template <> struct ArgTypeTraits<bool> {
   }
 };
 
+template <> struct ArgTypeTraits<double> {
+  static bool is(const VariantValue &Value) { return Value.isDouble(); }
+  static double get(const VariantValue &Value) {
+    return Value.getDouble();
+  }
+  static ArgKind getKind() {
+    return ArgKind(ArgKind::AK_Double);
+  }
+};
+
 template <> struct ArgTypeTraits<unsigned> {
   static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
   static unsigned get(const VariantValue &Value) {

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp Thu Jun  8 17:00:50 2017
@@ -130,8 +130,8 @@ private:
 
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
-      // Parse an unsigned literal.
-      consumeUnsignedLiteral(&Result);
+      // Parse an unsigned and float literal.
+      consumeNumberLiteral(&Result);
       break;
 
     default:
@@ -176,8 +176,9 @@ private:
     return Result;
   }
 
-  /// \brief Consume an unsigned literal.
-  void consumeUnsignedLiteral(TokenInfo *Result) {
+  /// \brief Consume an unsigned and float literal.
+  void consumeNumberLiteral(TokenInfo *Result) {
+    bool isFloatingLiteral = false;
     unsigned Length = 1;
     if (Code.size() > 1) {
       // Consume the 'x' or 'b' radix modifier, if present.
@@ -188,20 +189,43 @@ private:
     while (Length < Code.size() && isHexDigit(Code[Length]))
       ++Length;
 
+    // Try to recognize a floating point literal.
+    while (Length < Code.size()) {
+      char c = Code[Length];
+      if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {
+        isFloatingLiteral = true;
+        Length++;
+      } else {
+        break;
+      }
+    }
+
     Result->Text = Code.substr(0, Length);
     Code = Code.drop_front(Length);
 
-    unsigned Value;
-    if (!Result->Text.getAsInteger(0, Value)) {
-      Result->Kind = TokenInfo::TK_Literal;
-      Result->Value = Value;
+    if (isFloatingLiteral) {
+      char *end;
+      errno = 0;
+      double doubleValue = strtod(Result->Text.str().c_str(), &end);
+      if (*end == 0 && errno == 0) {
+        Result->Kind = TokenInfo::TK_Literal;
+        Result->Value = doubleValue;
+        return;
+      }
     } else {
-      SourceRange Range;
-      Range.Start = Result->Range.Start;
-      Range.End = currentLocation();
-      Error->addError(Range, Error->ET_ParserUnsignedError) << Result->Text;
-      Result->Kind = TokenInfo::TK_Error;
+      unsigned Value;
+      if (!Result->Text.getAsInteger(0, Value)) {
+        Result->Kind = TokenInfo::TK_Literal;
+        Result->Value = Value;
+        return;
+      }
     }
+
+    SourceRange Range;
+    Range.Start = Result->Range.Start;
+    Range.End = currentLocation();
+    Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;
+    Result->Kind = TokenInfo::TK_Error;
   }
 
   /// \brief Consume a string literal.

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp Thu Jun  8 17:00:50 2017
@@ -26,6 +26,8 @@ std::string ArgKind::asString() const {
     return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
   case AK_Boolean:
     return "boolean";
+  case AK_Double:
+    return "double";
   case AK_Unsigned:
     return "unsigned";
   case AK_String:
@@ -253,6 +255,10 @@ VariantValue::VariantValue(bool Boolean)
   setBoolean(Boolean);
 }
 
+VariantValue::VariantValue(double Double) : Type(VT_Nothing) {
+  setDouble(Double);
+}
+
 VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
   setUnsigned(Unsigned);
 }
@@ -274,6 +280,9 @@ VariantValue &VariantValue::operator=(co
   case VT_Boolean:
     setBoolean(Other.getBoolean());
     break;
+  case VT_Double:
+    setDouble(Other.getDouble());
+    break;
   case VT_Unsigned:
     setUnsigned(Other.getUnsigned());
     break;
@@ -300,6 +309,7 @@ void VariantValue::reset() {
     break;
   // Cases that do nothing.
   case VT_Boolean:
+  case VT_Double:
   case VT_Unsigned:
   case VT_Nothing:
     break;
@@ -322,6 +332,21 @@ void VariantValue::setBoolean(bool NewVa
   Value.Boolean = NewValue;
 }
 
+bool VariantValue::isDouble() const {
+  return Type == VT_Double;
+}
+
+double VariantValue::getDouble() const {
+  assert(isDouble());
+  return Value.Double;
+}
+
+void VariantValue::setDouble(double NewValue) {
+  reset();
+  Type = VT_Double;
+  Value.Double = NewValue;
+}
+
 bool VariantValue::isUnsigned() const {
   return Type == VT_Unsigned;
 }
@@ -375,6 +400,12 @@ bool VariantValue::isConvertibleTo(ArgKi
     *Specificity = 1;
     return true;
 
+  case ArgKind::AK_Double:
+    if (!isDouble())
+      return false;
+    *Specificity = 1;
+    return true;
+
   case ArgKind::AK_Unsigned:
     if (!isUnsigned())
       return false;
@@ -415,6 +446,7 @@ std::string VariantValue::getTypeAsStrin
   case VT_String: return "String";
   case VT_Matcher: return getMatcher().getTypeAsString();
   case VT_Boolean: return "Boolean";
+  case VT_Double: return "Double";
   case VT_Unsigned: return "Unsigned";
   case VT_Nothing: return "Nothing";
   }

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Thu Jun  8 17:00:50 2017
@@ -84,6 +84,21 @@ TEST(ParserTest, ParseBoolean) {
   EXPECT_EQ(false, Sema.Values[1].getBoolean());
 }
 
+TEST(ParserTest, ParseDouble) {
+  MockSema Sema;
+  Sema.parse("1.0");
+  Sema.parse("2.0f");
+  Sema.parse("34.56e-78");
+  Sema.parse("4.E+6");
+  Sema.parse("1");
+  EXPECT_EQ(5U, Sema.Values.size());
+  EXPECT_EQ(1.0, Sema.Values[0].getDouble());
+  EXPECT_EQ("1:1: Error parsing numeric literal: <2.0f>", Sema.Errors[1]);
+  EXPECT_EQ(34.56e-78, Sema.Values[2].getDouble());
+  EXPECT_EQ(4e+6, Sema.Values[3].getDouble());
+  EXPECT_FALSE(Sema.Values[4].isDouble());
+}
+
 TEST(ParserTest, ParseUnsigned) {
   MockSema Sema;
   Sema.parse("0");
@@ -95,8 +110,8 @@ TEST(ParserTest, ParseUnsigned) {
   EXPECT_EQ(0U, Sema.Values[0].getUnsigned());
   EXPECT_EQ(123U, Sema.Values[1].getUnsigned());
   EXPECT_EQ(31U, Sema.Values[2].getUnsigned());
-  EXPECT_EQ("1:1: Error parsing unsigned token: <12345678901>", Sema.Errors[3]);
-  EXPECT_EQ("1:1: Error parsing unsigned token: <1a1>", Sema.Errors[4]);
+  EXPECT_EQ("1:1: Error parsing numeric literal: <12345678901>", Sema.Errors[3]);
+  EXPECT_EQ("1:1: Error parsing numeric literal: <1a1>", Sema.Errors[4]);
 }
 
 TEST(ParserTest, ParseString) {

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=305021&r1=305020&r2=305021&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Thu Jun  8 17:00:50 2017
@@ -76,6 +76,7 @@ TEST(VariantValueTest, Assignment) {
   EXPECT_EQ("A", Value.getString());
   EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isBoolean());
+  EXPECT_FALSE(Value.isDouble());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_EQ("String", Value.getTypeAsString());
@@ -83,6 +84,7 @@ TEST(VariantValueTest, Assignment) {
   Value = VariantMatcher::SingleMatcher(recordDecl());
   EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isBoolean());
+  EXPECT_FALSE(Value.isDouble());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_TRUE(Value.isMatcher());
@@ -98,10 +100,20 @@ TEST(VariantValueTest, Assignment) {
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_FALSE(Value.isString());
 
+  Value = 3.14;
+  EXPECT_TRUE(Value.isDouble());
+  EXPECT_EQ(3.14, Value.getDouble());
+  EXPECT_TRUE(Value.hasValue());
+  EXPECT_FALSE(Value.isBoolean());
+  EXPECT_FALSE(Value.isUnsigned());
+  EXPECT_FALSE(Value.isMatcher());
+  EXPECT_FALSE(Value.isString());
+
   Value = 17;
   EXPECT_TRUE(Value.isUnsigned());
   EXPECT_EQ(17U, Value.getUnsigned());
   EXPECT_FALSE(Value.isBoolean());
+  EXPECT_FALSE(Value.isDouble());
   EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_FALSE(Value.isString());
@@ -109,6 +121,7 @@ TEST(VariantValueTest, Assignment) {
   Value = VariantValue();
   EXPECT_FALSE(Value.hasValue());
   EXPECT_FALSE(Value.isBoolean());
+  EXPECT_FALSE(Value.isDouble());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());




More information about the cfe-commits mailing list