Index: include/clang/ASTMatchers/Dynamic/Parser.h =================================================================== --- include/clang/ASTMatchers/Dynamic/Parser.h +++ include/clang/ASTMatchers/Dynamic/Parser.h @@ -19,8 +19,9 @@ /// \code /// Grammar for the expressions supported: /// := | | -/// := | +/// := | | /// := "quoted string" +/// := true | false /// := [0-9]+ /// := /// := () | Index: include/clang/ASTMatchers/Dynamic/VariantValue.h =================================================================== --- include/clang/ASTMatchers/Dynamic/VariantValue.h +++ include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -35,6 +35,7 @@ public: enum Kind { AK_Matcher, + AK_Boolean, AK_Unsigned, AK_String }; @@ -241,6 +242,7 @@ /// copy/assignment. /// /// Supported types: +/// - \c bool /// - \c unsigned /// - \c llvm::StringRef /// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher) @@ -253,14 +255,23 @@ VariantValue &operator=(const VariantValue &Other); /// \brief Specific constructors for each supported type. + VariantValue(bool Boolean); VariantValue(unsigned Unsigned); VariantValue(StringRef String); VariantValue(const VariantMatcher &Matchers); + /// \brief Constructs an \c unsigned value (disambiguation from bool). + VariantValue(int Signed) : VariantValue(static_cast(Signed)) {} + /// \brief Returns true iff this is not an empty value. explicit operator bool() const { return hasValue(); } bool hasValue() const { return Type != VT_Nothing; } + /// \brief Boolean value functions. + bool isBoolean() const; + bool getBoolean() const; + void setBoolean(bool Boolean); + /// \brief Unsigned value functions. bool isUnsigned() const; unsigned getUnsigned() const; @@ -303,6 +314,7 @@ /// \brief All supported value types. enum ValueType { VT_Nothing, + VT_Boolean, VT_Unsigned, VT_String, VT_Matcher @@ -311,6 +323,7 @@ /// \brief All supported value types. union AllValues { unsigned Unsigned; + bool Boolean; std::string *String; VariantMatcher *Matcher; }; Index: lib/ASTMatchers/Dynamic/Marshallers.h =================================================================== --- lib/ASTMatchers/Dynamic/Marshallers.h +++ lib/ASTMatchers/Dynamic/Marshallers.h @@ -65,6 +65,16 @@ } }; +template <> struct ArgTypeTraits { + static bool is(const VariantValue &Value) { return Value.isBoolean(); } + static bool get(const VariantValue &Value) { + return Value.getBoolean(); + } + static ArgKind getKind() { + return ArgKind(ArgKind::AK_Boolean); + } +}; + 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 @@ -153,8 +153,16 @@ break; ++TokenLength; } - Result.Kind = TokenInfo::TK_Ident; - Result.Text = Code.substr(0, TokenLength); + if (TokenLength == 4 && Code.startswith("true")) { + Result.Kind = TokenInfo::TK_Literal; + Result.Value = true; + } else if (TokenLength == 5 && Code.startswith("false")) { + Result.Kind = TokenInfo::TK_Literal; + Result.Value = false; + } else { + Result.Kind = TokenInfo::TK_Ident; + Result.Text = Code.substr(0, TokenLength); + } Code = Code.drop_front(TokenLength); } else { Result.Kind = TokenInfo::TK_InvalidChar; Index: lib/ASTMatchers/Dynamic/VariantValue.cpp =================================================================== --- lib/ASTMatchers/Dynamic/VariantValue.cpp +++ lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -24,6 +24,8 @@ switch (getArgKind()) { case AK_Matcher: return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); + case AK_Boolean: + return "boolean"; case AK_Unsigned: return "unsigned"; case AK_String: @@ -247,6 +249,10 @@ *this = Other; } +VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) { + setBoolean(Boolean); +} + VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { setUnsigned(Unsigned); } @@ -265,6 +271,9 @@ if (this == &Other) return *this; reset(); switch (Other.Type) { + case VT_Boolean: + setBoolean(Other.getBoolean()); + break; case VT_Unsigned: setUnsigned(Other.getUnsigned()); break; @@ -290,6 +299,7 @@ delete Value.Matcher; break; // Cases that do nothing. + case VT_Boolean: case VT_Unsigned: case VT_Nothing: break; @@ -297,6 +307,21 @@ Type = VT_Nothing; } +bool VariantValue::isBoolean() const { + return Type == VT_Boolean; +} + +bool VariantValue::getBoolean() const { + assert(isBoolean()); + return Value.Boolean; +} + +void VariantValue::setBoolean(bool NewValue) { + reset(); + Type = VT_Boolean; + Value.Boolean = NewValue; +} + bool VariantValue::isUnsigned() const { return Type == VT_Unsigned; } @@ -344,6 +369,12 @@ bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { switch (Kind.getArgKind()) { + case ArgKind::AK_Boolean: + if (!isBoolean()) + return false; + *Specificity = 1; + return true; + case ArgKind::AK_Unsigned: if (!isUnsigned()) return false; @@ -383,6 +414,7 @@ switch (Type) { case VT_String: return "String"; case VT_Matcher: return getMatcher().getTypeAsString(); + case VT_Boolean: return "Boolean"; 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 @@ -75,6 +75,15 @@ ExpectedMatchersTy ExpectedMatchers; }; +TEST(ParserTest, ParseBoolean) { + MockSema Sema; + Sema.parse("true"); + Sema.parse("false"); + EXPECT_EQ(2U, Sema.Values.size()); + EXPECT_EQ(true, Sema.Values[0].getBoolean()); + EXPECT_EQ(false, Sema.Values[1].getBoolean()); +} + TEST(ParserTest, ParseUnsigned) { MockSema Sema; Sema.parse("0"); Index: unittests/ASTMatchers/Dynamic/VariantValueTest.cpp =================================================================== --- unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -75,12 +75,14 @@ EXPECT_TRUE(Value.isString()); EXPECT_EQ("A", Value.getString()); EXPECT_TRUE(Value.hasValue()); + EXPECT_FALSE(Value.isBoolean()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isMatcher()); EXPECT_EQ("String", Value.getTypeAsString()); Value = VariantMatcher::SingleMatcher(recordDecl()); EXPECT_TRUE(Value.hasValue()); + EXPECT_FALSE(Value.isBoolean()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); EXPECT_TRUE(Value.isMatcher()); @@ -88,15 +90,25 @@ EXPECT_FALSE(Value.getMatcher().hasTypedMatcher()); EXPECT_EQ("Matcher", Value.getTypeAsString()); + Value = true; + EXPECT_TRUE(Value.isBoolean()); + EXPECT_EQ(true, Value.getBoolean()); + EXPECT_TRUE(Value.hasValue()); + 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_TRUE(Value.hasValue()); EXPECT_FALSE(Value.isMatcher()); EXPECT_FALSE(Value.isString()); Value = VariantValue(); EXPECT_FALSE(Value.hasValue()); + EXPECT_FALSE(Value.isBoolean()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); EXPECT_FALSE(Value.isMatcher());