diff options
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/Parser.h | 37 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/VariantValue.h | 6 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Parser.cpp | 48 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp | 23 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp | 7 |
5 files changed, 95 insertions, 26 deletions
diff --git a/clang/include/clang/ASTMatchers/Dynamic/Parser.h b/clang/include/clang/ASTMatchers/Dynamic/Parser.h index 5901495bddb..896b07010ca 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Parser.h @@ -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,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<MatcherCtor> lookupMatcherCtor(StringRef MatcherName, + const SourceRange &NameRange, + Diagnostics *Error) 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. /// /// This overload creates matchers calling directly into the registry. If the diff --git a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h index c6853572ec8..cd7395b4157 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/clang/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<DynTypedMatcher> Matchers); + static VariantMatcher + PolymorphicMatcher(std::vector<DynTypedMatcher> 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/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp index 24ffdcda51b..bc6f73ca452 100644 --- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/clang/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<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, const SourceRange &NameRange, Diagnostics *Error) { + return Registry::lookupMatcherCtor(MatcherName, NameRange, Error); +} + +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) { diff --git a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp index cdf4f92db65..fdfacf18188 100644 --- a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/clang/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<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()); diff --git a/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp index e62a4645f75..8d6e767f550 100644 --- a/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ b/clang/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()); |

