r206176 - Add support for named values in the parser.

Samuel Benzaquen sbenza at google.com
Mon Apr 14 06:51:21 PDT 2014


Author: sbenza
Date: Mon Apr 14 08:51:21 2014
New Revision: 206176

URL: http://llvm.org/viewvc/llvm-project?rev=206176&view=rev
Log:
Add support for named values in the parser.

Summary: Add support for named values in the parser.

Reviewers: pcc

CC: cfe-commits, klimek

Differential Revision: http://llvm-reviews.chandlerc.com/D3276

Modified:
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.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=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Mon Apr 14 08:51:21 2014
@@ -60,11 +60,12 @@ public:
   enum ErrorType {
     ET_None = 0,
 
-    ET_RegistryNotFound = 1,
+    ET_RegistryMatcherNotFound = 1,
     ET_RegistryWrongArgCount = 2,
     ET_RegistryWrongArgType = 3,
     ET_RegistryNotBindable = 4,
     ET_RegistryAmbiguousOverload = 5,
+    ET_RegistryValueNotFound = 6,
 
     ET_ParserStringError = 100,
     ET_ParserNoOpenParen = 101,

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=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h Mon Apr 14 08:51:21 2014
@@ -18,13 +18,14 @@
 ///
 /// \code
 /// Grammar for the expressions supported:
-/// <Expression>        := <Literal> | <MatcherExpression>
+/// <Expression>        := <Literal> | <NamedValue> | <MatcherExpression>
 /// <Literal>           := <StringLiteral> | <Unsigned>
 /// <StringLiteral>     := "quoted string"
 /// <Unsigned>          := [0-9]+
-/// <MatcherExpression> := <MatcherName>(<ArgumentList>) |
-///                        <MatcherName>(<ArgumentList>).bind(<StringLiteral>)
-/// <MatcherName>       := [a-zA-Z]+
+/// <NamedValue>        := <Identifier>
+/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
+///                        <Identifier>(<ArgumentList>).bind(<StringLiteral>)
+/// <Identifier>        := [a-zA-Z]+
 /// <ArgumentList>      := <Expression> | <Expression>,<ArgumentList>
 /// \endcode
 ///
@@ -62,6 +63,17 @@ public:
   public:
     virtual ~Sema();
 
+    /// \brief Lookup a value by name.
+    ///
+    /// This can be used in the Sema layer to declare known constants or to
+    /// allow to split an expression in pieces.
+    ///
+    /// \param Name The name of the value to lookup.
+    ///
+    /// \return The named value. It could be any type that VariantValue
+    ///   supports. An empty value means that the name is not recognized.
+    virtual VariantValue getNamedValue(StringRef Name);
+
     /// \brief Process a matcher expression.
     ///
     /// All the arguments passed here have already been processed.
@@ -89,15 +101,26 @@ public:
     ///
     /// \param MatcherName The matcher name found by the parser.
     ///
-    /// \param NameRange The location of the name in the matcher source.
-    ///   Useful for error reporting.
-    ///
-    /// \return The matcher constructor, or Optional<MatcherCtor>() if an error
-    ///   occurred. In that case, \c Error will contain a description of the
-    ///   error.
+    /// \return The matcher constructor, or Optional<MatcherCtor>() if not
+    /// found.
     virtual llvm::Optional<MatcherCtor>
-    lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
-                      Diagnostics *Error) = 0;
+    lookupMatcherCtor(StringRef MatcherName) = 0;
+  };
+
+  /// \brief Sema implementation that uses the matcher registry to process the
+  ///   tokens.
+  class RegistrySema : public Parser::Sema {
+   public:
+    virtual ~RegistrySema();
+
+    llvm::Optional<MatcherCtor>
+    lookupMatcherCtor(StringRef MatcherName) override;
+
+    VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
+                                          const SourceRange &NameRange,
+                                          StringRef BindID,
+                                          ArrayRef<ParserValue> Args,
+                                          Diagnostics *Error) override;
   };
 
   /// \brief Parse a matcher expression, creating matchers from the registry.
@@ -160,7 +183,9 @@ private:
          Diagnostics *Error);
 
   bool parseExpressionImpl(VariantValue *Value);
-  bool parseMatcherExpressionImpl(VariantValue *Value);
+  bool parseMatcherExpressionImpl(const TokenInfo &NameToken,
+                                  VariantValue *Value);
+  bool parseIdentifierPrefixImpl(VariantValue *Value);
 
   void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
                      StringRef Decl);

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h Mon Apr 14 08:51:21 2014
@@ -55,11 +55,8 @@ public:
   /// \brief Look up a matcher in the registry by name,
   ///
   /// \return An opaque value which may be used to refer to the matcher
-  /// constructor, or Optional<MatcherCtor>() if not found.  In that case
-  /// \c Error will contain the description of the error.
-  static llvm::Optional<MatcherCtor>
-  lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
-                    Diagnostics *Error);
+  /// constructor, or Optional<MatcherCtor>() if not found.
+  static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName);
 
   /// \brief Compute the list of completions for \p Context.
   ///

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=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Mon Apr 14 08:51:21 2014
@@ -78,7 +78,8 @@ public:
   /// \brief Clones the provided matchers.
   ///
   /// They should be the result of a polymorphic matcher.
-  static VariantMatcher PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
+  static VariantMatcher
+  PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
 
   /// \brief Creates a 'variadic' operator matcher.
   ///
@@ -208,6 +209,10 @@ public:
   VariantValue(const std::string &String);
   VariantValue(const VariantMatcher &Matchers);
 
+  /// \brief Returns true iff this is not an empty value.
+  LLVM_EXPLICIT operator bool() const { return hasValue(); }
+  bool hasValue() const { return Type != VT_Nothing; }
+
   /// \brief Unsigned value functions.
   bool isUnsigned() const;
   unsigned getUnsigned() const;

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Mon Apr 14 08:51:21 2014
@@ -87,7 +87,7 @@ StringRef contextTypeToFormatString(Diag
 
 StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
   switch (Type) {
-  case Diagnostics::ET_RegistryNotFound:
+  case Diagnostics::ET_RegistryMatcherNotFound:
     return "Matcher not found: $0";
   case Diagnostics::ET_RegistryWrongArgCount:
     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
@@ -98,6 +98,8 @@ StringRef errorTypeToFormatString(Diagno
   case Diagnostics::ET_RegistryAmbiguousOverload:
     // TODO: Add type info about the overload error.
     return "Ambiguous matcher overload.";
+  case Diagnostics::ET_RegistryValueNotFound:
+    return "Value not found: $0";
 
   case Diagnostics::ET_ParserStringError:
     return "Error parsing string token: <$0>";

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp Mon Apr 14 08:51:21 2014
@@ -258,6 +258,10 @@ private:
 
 Parser::Sema::~Sema() {}
 
+VariantValue Parser::Sema::getNamedValue(StringRef Name) {
+  return VariantValue();
+}
+
 struct Parser::ScopedContextEntry {
   Parser *P;
 
@@ -274,12 +278,43 @@ struct Parser::ScopedContextEntry {
   }
 };
 
+/// \brief Parse expressions that start with an identifier.
+///
+/// This function can parse named values and matchers.
+/// In case of failure it will try to determine the user's intent to give
+/// an appropriate error message.
+bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
+  const TokenInfo NameToken = Tokenizer->consumeNextToken();
+
+  if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
+    // Parse as a named value.
+    if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) {
+      *Value = NamedValue;
+      return true;
+    }
+    // If the syntax is correct and the name is not a matcher either, report
+    // unknown named value.
+    if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||
+         Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||
+         Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&
+        !S->lookupMatcherCtor(NameToken.Text)) {
+      Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
+          << NameToken.Text;
+      return false;
+    }
+    // Otherwise, fallback to the matcher parser.
+  }
+
+  // Parse as a matcher expression.
+  return parseMatcherExpressionImpl(NameToken, Value);
+}
+
 /// \brief Parse and validate a matcher expression.
 /// \return \c true on success, in which case \c Value has the matcher parsed.
 ///   If the input is malformed, or some argument has an error, it
 ///   returns \c false.
-bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
-  const TokenInfo NameToken = Tokenizer->consumeNextToken();
+bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
+                                        VariantValue *Value) {
   assert(NameToken.Kind == TokenInfo::TK_Ident);
   const TokenInfo OpenToken = Tokenizer->consumeNextToken();
   if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
@@ -288,8 +323,14 @@ bool Parser::parseMatcherExpressionImpl(
     return false;
   }
 
-  llvm::Optional<MatcherCtor> Ctor =
-      S->lookupMatcherCtor(NameToken.Text, NameToken.Range, Error);
+  llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
+
+  if (!Ctor) {
+    Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
+        << NameToken.Text;
+    // Do not return here. We need to continue to give completion suggestions.
+  }
+
   std::vector<ParserValue> Args;
   TokenInfo EndToken;
 
@@ -425,7 +466,7 @@ bool Parser::parseExpressionImpl(Variant
     return true;
 
   case TokenInfo::TK_Ident:
-    return parseMatcherExpressionImpl(Value);
+    return parseIdentifierPrefixImpl(Value);
 
   case TokenInfo::TK_CodeCompletion:
     addExpressionCompletions();
@@ -457,27 +498,23 @@ Parser::Parser(CodeTokenizer *Tokenizer,
                Diagnostics *Error)
     : Tokenizer(Tokenizer), S(S), Error(Error) {}
 
-class RegistrySema : public Parser::Sema {
-public:
-  virtual ~RegistrySema() {}
-  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
-                                                const SourceRange &NameRange,
-                                                Diagnostics *Error) {
-    return Registry::lookupMatcherCtor(MatcherName, NameRange, Error);
-  }
-  VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
-                                        const SourceRange &NameRange,
-                                        StringRef BindID,
-                                        ArrayRef<ParserValue> Args,
-                                        Diagnostics *Error) {
-    if (BindID.empty()) {
-      return Registry::constructMatcher(Ctor, NameRange, Args, Error);
-    } else {
-      return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
-                                             Error);
-    }
+Parser::RegistrySema::~RegistrySema() {}
+
+llvm::Optional<MatcherCtor>
+Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
+  return Registry::lookupMatcherCtor(MatcherName);
+}
+
+VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
+    MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID,
+    ArrayRef<ParserValue> Args, Diagnostics *Error) {
+  if (BindID.empty()) {
+    return Registry::constructMatcher(Ctor, NameRange, Args, Error);
+  } else {
+    return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
+                                           Error);
   }
-};
+}
 
 bool Parser::parseExpression(StringRef Code, VariantValue *Value,
                              Diagnostics *Error) {

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Mon Apr 14 08:51:21 2014
@@ -325,17 +325,12 @@ static llvm::ManagedStatic<RegistryMaps>
 } // anonymous namespace
 
 // static
-llvm::Optional<MatcherCtor>
-Registry::lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
-                            Diagnostics *Error) {
+llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
   ConstructorMap::const_iterator it =
       RegistryData->constructors().find(MatcherName);
-  if (it == RegistryData->constructors().end()) {
-    Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName;
-    return llvm::Optional<MatcherCtor>();
-  }
-
-  return it->second;
+  return it == RegistryData->constructors().end()
+             ? llvm::Optional<MatcherCtor>()
+             : it->second;
 }
 
 namespace {

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Mon Apr 14 08:51:21 2014
@@ -39,9 +39,7 @@ public:
     Errors.push_back(Error.toStringFull());
   }
 
-  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
-                                                const SourceRange &NameRange,
-                                                Diagnostics *Error) {
+  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
     const ExpectedMatchersTy::value_type *Matcher =
         &*ExpectedMatchers.find(MatcherName);
     return reinterpret_cast<MatcherCtor>(Matcher);
@@ -175,6 +173,29 @@ TEST(ParserTest, FullParserTest) {
   EXPECT_TRUE(matches("void f(int a, int x);", M));
   EXPECT_FALSE(matches("void f(int x, int a);", M));
 
+  // Test named values.
+  struct NamedSema : public Parser::RegistrySema {
+   public:
+    virtual VariantValue getNamedValue(StringRef Name) {
+      if (Name == "nameX")
+        return std::string("x");
+      if (Name == "param0")
+        return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
+      return VariantValue();
+    }
+  };
+  NamedSema Sema;
+  llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
+      Parser::parseMatcherExpression(
+          "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
+          &Error));
+  EXPECT_EQ("", Error.toStringFull());
+  M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
+
+  EXPECT_TRUE(matches("void f(int a, int x);", M));
+  EXPECT_FALSE(matches("void f(int x, int a);", M));
+
+
   EXPECT_TRUE(!Parser::parseMatcherExpression(
                    "hasInitializer(\n    binaryOperator(hasLHS(\"A\")))",
                    &Error).hasValue());
@@ -208,6 +229,10 @@ TEST(ParserTest, Errors) {
       "1:9: Error parsing matcher. Found token <123> while looking for ','.",
       ParseWithError("Foo(\"A\" 123)"));
   EXPECT_EQ(
+      "1:1: Error parsing argument 1 for matcher stmt.\n"
+      "1:6: Value not found: someValue",
+      ParseWithError("stmt(someValue)"));
+  EXPECT_EQ(
       "1:1: Matcher not found: Foo\n"
       "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
       ParseWithError("Foo("));

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Mon Apr 14 08:51:21 2014
@@ -35,21 +35,15 @@ public:
     return Out;
   }
 
-  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
-                                                Diagnostics *Error = 0) {
-    Diagnostics DummyError;
-    if (!Error) Error = &DummyError;
-    llvm::Optional<MatcherCtor> Ctor =
-        Registry::lookupMatcherCtor(MatcherName, SourceRange(), Error);
-    EXPECT_EQ("", DummyError.toStringFull());
-    return Ctor;
+  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
+    return Registry::lookupMatcherCtor(MatcherName);
   }
 
   VariantMatcher constructMatcher(StringRef MatcherName,
                                   Diagnostics *Error = NULL) {
     Diagnostics DummyError;
     if (!Error) Error = &DummyError;
-    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     VariantMatcher Out;
     if (Ctor)
       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
@@ -62,7 +56,7 @@ public:
                                   Diagnostics *Error = NULL) {
     Diagnostics DummyError;
     if (!Error) Error = &DummyError;
-    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     VariantMatcher Out;
     if (Ctor)
       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
@@ -76,7 +70,7 @@ public:
                                   Diagnostics *Error = NULL) {
     Diagnostics DummyError;
     if (!Error) Error = &DummyError;
-    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
     VariantMatcher Out;
     if (Ctor)
       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=206176&r1=206175&r2=206176&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Mon Apr 14 08:51:21 2014
@@ -26,6 +26,7 @@ TEST(VariantValueTest, Unsigned) {
   EXPECT_TRUE(Value.isUnsigned());
   EXPECT_EQ(kUnsigned, Value.getUnsigned());
 
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());
 }
@@ -38,6 +39,7 @@ TEST(VariantValueTest, String) {
   EXPECT_EQ(kString, Value.getString());
   EXPECT_EQ("String", Value.getTypeAsString());
 
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isMatcher());
 }
@@ -45,6 +47,7 @@ TEST(VariantValueTest, String) {
 TEST(VariantValueTest, DynTypedMatcher) {
   VariantValue Value = VariantMatcher::SingleMatcher(stmt());
 
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
 
@@ -74,11 +77,13 @@ TEST(VariantValueTest, Assignment) {
   VariantValue Value = std::string("A");
   EXPECT_TRUE(Value.isString());
   EXPECT_EQ("A", Value.getString());
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_EQ("String", Value.getTypeAsString());
 
   Value = VariantMatcher::SingleMatcher(recordDecl());
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_TRUE(Value.isMatcher());
@@ -89,16 +94,36 @@ TEST(VariantValueTest, Assignment) {
   Value = 17;
   EXPECT_TRUE(Value.isUnsigned());
   EXPECT_EQ(17U, Value.getUnsigned());
+  EXPECT_TRUE(Value.hasValue());
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_FALSE(Value.isString());
 
   Value = VariantValue();
+  EXPECT_FALSE(Value.hasValue());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());
   EXPECT_EQ("Nothing", Value.getTypeAsString());
 }
 
+TEST(VariantValueTest, ImplicitBool) {
+  VariantValue Value;
+  bool IfTrue = false;
+  if (Value) {
+    IfTrue = true;
+  }
+  EXPECT_FALSE(IfTrue);
+  EXPECT_TRUE(!Value);
+
+  Value = std::string();
+  IfTrue = false;
+  if (Value) {
+    IfTrue = true;
+  }
+  EXPECT_TRUE(IfTrue);
+  EXPECT_FALSE(!Value);
+}
+
 TEST(VariantValueTest, Matcher) {
   EXPECT_TRUE(matches("class X {};", VariantValue(VariantMatcher::SingleMatcher(
                                                       recordDecl(hasName("X"))))





More information about the cfe-commits mailing list