summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h2
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h3
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h10
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h10
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp50
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp32
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp19
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp13
9 files changed, 124 insertions, 19 deletions
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 2c76ddaa07..908fa0db62 100644
--- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -76,7 +76,7 @@ public:
ET_ParserInvalidToken = 106,
ET_ParserMalformedBindExpr = 107,
ET_ParserTrailingCode = 108,
- ET_ParserUnsignedError = 109,
+ ET_ParserNumberError = 109,
ET_ParserOverloadedType = 110
};
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index cd3b30ab84..5ec4a9abf4 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -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>) |
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index ce00bf7fe2..f9efe0f16f 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -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 final : VariantMatcher::MatcherOps {
///
/// 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;
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index 787b780c42..9cddcf93ca 100644
--- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -118,8 +118,8 @@ static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
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";
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index 1d4ba037fd..c557ff1626 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -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) {
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
index 967da8ac32..ff5c5fb657 100644
--- a/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -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.
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index a889e46fd6..57858d00ac 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -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) : Type(VT_Nothing) {
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=(const VariantValue &Other) {
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 NewValue) {
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(ArgKind Kind, unsigned *Specificity) const {
*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::getTypeAsString() const {
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";
}
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 504724362a..ed184a8c14 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -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) {
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index ca0eb90285..7d3a07028a 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -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());