]> granicus.if.org Git - clang/commitdiff
[ASTMatchers] Add support for boolean literals
authorPeter Wu <peter@lekensteyn.nl>
Thu, 8 Jun 2017 22:00:38 +0000 (22:00 +0000)
committerPeter Wu <peter@lekensteyn.nl>
Thu, 8 Jun 2017 22:00:38 +0000 (22:00 +0000)
Summary:
Recognize boolean literals for future extensions ("equals(true)").
Note that a specific VariantValue constructor is added to resolve
ambiguity (like "Value = 5") between unsigned and bool.

Reviewed By: aaron.ballman

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@305020 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/ASTMatchers/Dynamic/Parser.h
include/clang/ASTMatchers/Dynamic/VariantValue.h
lib/ASTMatchers/Dynamic/Marshallers.h
lib/ASTMatchers/Dynamic/Parser.cpp
lib/ASTMatchers/Dynamic/VariantValue.cpp
unittests/ASTMatchers/Dynamic/ParserTest.cpp
unittests/ASTMatchers/Dynamic/VariantValueTest.cpp

index 76926f09dbcbdce2ceb9abbd20abaabab2115495..cd3b30ab8420af799089f2a72f2d98990f3192f1 100644 (file)
@@ -19,8 +19,9 @@
 /// \code
 /// Grammar for the expressions supported:
 /// <Expression>        := <Literal> | <NamedValue> | <MatcherExpression>
-/// <Literal>           := <StringLiteral> | <Unsigned>
+/// <Literal>           := <StringLiteral> | <Boolean> | <Unsigned>
 /// <StringLiteral>     := "quoted string"
+/// <Boolean>           := true | false
 /// <Unsigned>          := [0-9]+
 /// <NamedValue>        := <Identifier>
 /// <MatcherExpression> := <Identifier>(<ArgumentList>) |
index c5426dd75ef5caab74f5fabe5676abcbdb3c24e9..ce00bf7fe27fc640e4aee44ecdf90726cec06637 100644 (file)
@@ -35,6 +35,7 @@ class ArgKind {
  public:
   enum Kind {
     AK_Matcher,
+    AK_Boolean,
     AK_Unsigned,
     AK_String
   };
@@ -241,6 +242,7 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
 /// copy/assignment.
 ///
 /// Supported types:
+///  - \c bool
 ///  - \c unsigned
 ///  - \c llvm::StringRef
 ///  - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
@@ -253,14 +255,23 @@ public:
   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<unsigned>(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 @@ private:
   /// \brief All supported value types.
   enum ValueType {
     VT_Nothing,
+    VT_Boolean,
     VT_Unsigned,
     VT_String,
     VT_Matcher
@@ -311,6 +323,7 @@ private:
   /// \brief All supported value types.
   union AllValues {
     unsigned Unsigned;
+    bool Boolean;
     std::string *String;
     VariantMatcher *Matcher;
   };
index fb6b349a811c7341ca7e4dcab02c11c23c6161fe..1d4ba037fde5feb00c127e6928c05fbd6e567d27 100644 (file)
@@ -65,6 +65,16 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
   }
 };
 
+template <> struct ArgTypeTraits<bool> {
+  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<unsigned> {
   static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
   static unsigned get(const VariantValue &Value) {
index ce8d0a9a02062c869be80660a61deb8dfa22faff..967da8ac322f837f0d035b228a23a18e5618e1a7 100644 (file)
@@ -153,8 +153,16 @@ private:
             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 f0339ed479cd64f810a7adfe52dfa3ef59387c25..a889e46fd6a138b11f17f93be2271bacf756cfea 100644 (file)
@@ -24,6 +24,8 @@ std::string ArgKind::asString() const {
   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 @@ VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
   *this = Other;
 }
 
+VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
+  setBoolean(Boolean);
+}
+
 VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
   setUnsigned(Unsigned);
 }
@@ -265,6 +271,9 @@ VariantValue &VariantValue::operator=(const VariantValue &Other) {
   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 @@ void VariantValue::reset() {
     delete Value.Matcher;
     break;
   // Cases that do nothing.
+  case VT_Boolean:
   case VT_Unsigned:
   case VT_Nothing:
     break;
@@ -297,6 +307,21 @@ void VariantValue::reset() {
   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 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) {
 
 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 @@ std::string VariantValue::getTypeAsString() const {
   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 d241f5ba2f86e5c2c57a88c5f89ceb97d62ff35e..504724362a789be81bf2eb4a1a3ee91e0e17d35e 100644 (file)
@@ -75,6 +75,15 @@ public:
   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 9df7b780d47f68e3643fe9247fcb5015d4138e61..ca0eb9028584f813642b6c5f4c8f9aec0c00e888 100644 (file)
@@ -75,12 +75,14 @@ TEST(VariantValueTest, Assignment) {
   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 @@ TEST(VariantValueTest, Assignment) {
   EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
   EXPECT_EQ("Matcher<Decl>", 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());