From 62060a01e095cf35eb9ca42a333752d12714f35c Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Wed, 2 Apr 2014 13:11:45 +0000 Subject: [PATCH] Add support for named values in the parser. Summary: Add support for named values in the parser. This allows injection of arbitrary constants using a custom Sema object. Completions are not supported right now. Will be used by clang_query to support the 'let' command. Usage example: clang_query> let unique_ptr recordDecl(hasName("unique_ptr")) clang_query> match varDecl(hasType(unique_ptr)) Reviewers: klimek, pcc CC: cfe-commits, klimek Differential Revision: http://llvm-reviews.chandlerc.com/D3229 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205419 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/ASTMatchers/Dynamic/Parser.h | 37 ++++++++++++-- .../clang/ASTMatchers/Dynamic/VariantValue.h | 6 ++- lib/ASTMatchers/Dynamic/Parser.cpp | 48 +++++++++++-------- unittests/ASTMatchers/Dynamic/ParserTest.cpp | 23 +++++++++ .../ASTMatchers/Dynamic/VariantValueTest.cpp | 7 +++ 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h index 5901495bdd..896b07010c 100644 --- a/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/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: 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 @@ public: 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 diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index c6853572ec..cd7395b415 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -78,7 +78,8 @@ public: /// \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 @@ public: 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; diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 24ffdcda51..bc6f73ca45 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -424,8 +424,18 @@ bool Parser::parseExpressionImpl(VariantValue *Value) { *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 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, 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) { diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index cdf4f92db6..fdfacf1818 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -175,6 +175,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 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()); diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp index e62a4645f7..8d6e767f55 100644 --- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -26,6 +26,7 @@ TEST(VariantValueTest, Unsigned) { 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 @@ TEST(VariantValueTest, String) { 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, String) { TEST(VariantValueTest, DynTypedMatcher) { VariantValue Value = VariantMatcher::SingleMatcher(stmt()); + EXPECT_FALSE(Value.isNothing()); 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_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 @@ TEST(VariantValueTest, Assignment) { 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()); -- 2.40.0