Index: include/clang/ASTMatchers/Dynamic/Diagnostics.h =================================================================== --- include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -76,7 +76,7 @@ ET_ParserInvalidToken = 106, ET_ParserMalformedBindExpr = 107, ET_ParserTrailingCode = 108, - ET_ParserUnsignedError = 109, + ET_ParserNumberError = 109, ET_ParserOverloadedType = 110 }; Index: include/clang/ASTMatchers/Dynamic/Parser.h =================================================================== --- include/clang/ASTMatchers/Dynamic/Parser.h +++ include/clang/ASTMatchers/Dynamic/Parser.h @@ -19,9 +19,10 @@ /// \code /// Grammar for the expressions supported: /// := | | -/// := | | +/// := | | | /// := "quoted string" /// := true | false +/// := 1.0 | 2e-3 | 3.45e67 /// := [0-9]+ /// := /// := () | Index: include/clang/ASTMatchers/Dynamic/VariantValue.h =================================================================== --- include/clang/ASTMatchers/Dynamic/VariantValue.h +++ include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -36,6 +36,7 @@ enum Kind { AK_Matcher, AK_Boolean, + AK_Double, AK_Unsigned, AK_String }; @@ -243,6 +244,7 @@ /// /// Supported types: /// - \c bool +// - \c double /// - \c unsigned /// - \c llvm::StringRef /// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher) @@ -256,6 +258,7 @@ /// \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 @@ 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 @@ enum ValueType { VT_Nothing, VT_Boolean, + VT_Double, VT_Unsigned, VT_String, VT_Matcher @@ -323,6 +332,7 @@ /// \brief All supported value types. union AllValues { unsigned Unsigned; + double Double; bool Boolean; std::string *String; VariantMatcher *Matcher; Index: lib/ASTMatchers/Dynamic/Diagnostics.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -118,8 +118,8 @@ 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"; Index: lib/ASTMatchers/Dynamic/Marshallers.h =================================================================== --- lib/ASTMatchers/Dynamic/Marshallers.h +++ lib/ASTMatchers/Dynamic/Marshallers.h @@ -75,6 +75,16 @@ } }; +template <> struct ArgTypeTraits { + 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 { static bool is(const VariantValue &Value) { return Value.isUnsigned(); } static unsigned get(const VariantValue &Value) { Index: lib/ASTMatchers/Dynamic/Parser.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Parser.cpp +++ lib/ASTMatchers/Dynamic/Parser.cpp @@ -178,6 +178,7 @@ /// \brief Consume an unsigned literal. void consumeUnsignedLiteral(TokenInfo *Result) { + bool isFloatingLiteral = false; unsigned Length = 1; if (Code.size() > 1) { // Consume the 'x' or 'b' radix modifier, if present. @@ -188,20 +189,42 @@ 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; + double doubleValue = strtod(Result->Text.str().c_str(), &end); + if (*end == 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. Index: lib/ASTMatchers/Dynamic/VariantValue.cpp =================================================================== --- lib/ASTMatchers/Dynamic/VariantValue.cpp +++ lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -26,6 +26,8 @@ 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 @@ setBoolean(Boolean); } +VariantValue::VariantValue(double Double) : Type(VT_Nothing) { + setDouble(Double); +} + VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { setUnsigned(Unsigned); } @@ -274,6 +280,9 @@ 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 @@ break; // Cases that do nothing. case VT_Boolean: + case VT_Double: case VT_Unsigned: case VT_Nothing: break; @@ -322,6 +332,21 @@ 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 @@ *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 @@ 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"; } Index: unittests/ASTMatchers/Dynamic/ParserTest.cpp =================================================================== --- unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -84,6 +84,21 @@ 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 @@ 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) { Index: unittests/ASTMatchers/Dynamic/VariantValueTest.cpp =================================================================== --- unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -76,6 +76,7 @@ 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 @@ 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 @@ 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 @@ 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());