Index: include/clang/ASTMatchers/Dynamic/Parser.h =================================================================== --- include/clang/ASTMatchers/Dynamic/Parser.h +++ include/clang/ASTMatchers/Dynamic/Parser.h @@ -18,13 +18,14 @@ /// /// \code /// Grammar for the expressions supported: -/// := | +/// := | | /// := | /// := "quoted string" /// := [0-9]+ -/// := () | -/// ().bind() -/// := [a-zA-Z]+ +/// := +/// := () | +/// ().bind() +/// := [a-zA-Z]+ /// := | , /// \endcode /// @@ -62,6 +63,19 @@ 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. A 'nothing' value means that the name is not recognized. + virtual VariantValue getNamedValue(StringRef Name) { + return VariantValue(); + } + /// \brief Process a matcher expression. /// /// All the arguments passed here have already been processed. @@ -100,6 +114,21 @@ Diagnostics *Error) = 0; }; + /// \brief Sema implementation that uses the matcher registry to process the + /// tokens. + class RegistrySema : public Parser::Sema { + public: + virtual ~RegistrySema(); + llvm::Optional lookupMatcherCtor(StringRef MatcherName, + const SourceRange &NameRange, + Diagnostics *Error) override; + VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error) override; + }; + /// \brief Parse a matcher expression, creating matchers from the registry. /// /// This overload creates matchers calling directly into the registry. If the Index: include/clang/ASTMatchers/Dynamic/VariantValue.h =================================================================== --- include/clang/ASTMatchers/Dynamic/VariantValue.h +++ include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -78,7 +78,8 @@ /// \brief Clones the provided matchers. /// /// They should be the result of a polymorphic matcher. - static VariantMatcher PolymorphicMatcher(std::vector Matchers); + static VariantMatcher + PolymorphicMatcher(std::vector Matchers); /// \brief Creates a 'variadic' operator matcher. /// @@ -208,6 +209,9 @@ VariantValue(const std::string &String); VariantValue(const VariantMatcher &Matchers); + /// \brief Returns true iff this is an empty value. + bool isNothing() const { return Type == VT_Nothing; } + /// \brief Unsigned value functions. bool isUnsigned() const; unsigned getUnsigned() const; Index: lib/ASTMatchers/Dynamic/Parser.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Parser.cpp +++ lib/ASTMatchers/Dynamic/Parser.cpp @@ -424,8 +424,18 @@ *Value = Tokenizer->consumeNextToken().Value; return true; - case TokenInfo::TK_Ident: + case TokenInfo::TK_Ident: { + // Identifier could be a name known by Sema as a named value. + const VariantValue NamedValue = + S->getNamedValue(Tokenizer->peekNextToken().Text); + if (!NamedValue.isNothing()) { + Tokenizer->consumeNextToken(); // Actually consume it. + *Value = NamedValue; + return true; + } + // Fallback to full matcher parsing. return parseMatcherExpressionImpl(Value); + } case TokenInfo::TK_CodeCompletion: addExpressionCompletions(); @@ -457,27 +467,23 @@ Diagnostics *Error) : Tokenizer(Tokenizer), S(S), Error(Error) {} -class RegistrySema : public Parser::Sema { -public: - virtual ~RegistrySema() {} - llvm::Optional lookupMatcherCtor(StringRef MatcherName, - const SourceRange &NameRange, - Diagnostics *Error) { - return Registry::lookupMatcherCtor(MatcherName, NameRange, Error); - } - VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef 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 Parser::RegistrySema::lookupMatcherCtor( + StringRef MatcherName, const SourceRange &NameRange, Diagnostics *Error) { + return Registry::lookupMatcherCtor(MatcherName, NameRange, Error); +} + +VariantMatcher Parser::RegistrySema::actOnMatcherExpression( + MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID, + ArrayRef 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) { Index: unittests/ASTMatchers/Dynamic/ParserTest.cpp =================================================================== --- unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -175,6 +175,29 @@ 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 HasParameterWithNamedValues( + Parser::parseMatcherExpression( + "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema, + &Error)); + EXPECT_EQ("", Error.toStringFull()); + M = HasParameterWithNamedValues->unconditionalConvertTo(); + + 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()); Index: unittests/ASTMatchers/Dynamic/VariantValueTest.cpp =================================================================== --- unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -26,6 +26,7 @@ EXPECT_TRUE(Value.isUnsigned()); EXPECT_EQ(kUnsigned, Value.getUnsigned()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isString()); EXPECT_FALSE(Value.isMatcher()); } @@ -38,6 +39,7 @@ EXPECT_EQ(kString, Value.getString()); EXPECT_EQ("String", Value.getTypeAsString()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isMatcher()); } @@ -45,6 +47,7 @@ TEST(VariantValueTest, DynTypedMatcher) { VariantValue Value = VariantMatcher::SingleMatcher(stmt()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); @@ -74,11 +77,13 @@ VariantValue Value = std::string("A"); EXPECT_TRUE(Value.isString()); EXPECT_EQ("A", Value.getString()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isMatcher()); EXPECT_EQ("String", Value.getTypeAsString()); Value = VariantMatcher::SingleMatcher(recordDecl()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); EXPECT_TRUE(Value.isMatcher()); @@ -89,10 +94,12 @@ Value = 17; EXPECT_TRUE(Value.isUnsigned()); EXPECT_EQ(17U, Value.getUnsigned()); + EXPECT_FALSE(Value.isNothing()); EXPECT_FALSE(Value.isMatcher()); EXPECT_FALSE(Value.isString()); Value = VariantValue(); + EXPECT_TRUE(Value.isNothing()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); EXPECT_FALSE(Value.isMatcher());