13 changes: 13 additions & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(thisPointerType);

REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(addrLabelExpr);
REGISTER_MATCHER(alignOfExpr);
REGISTER_MATCHER(allOf);
REGISTER_MATCHER(anyOf);
Expand All @@ -104,9 +105,11 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(arrayType);
REGISTER_MATCHER(asmStmt);
REGISTER_MATCHER(asString);
REGISTER_MATCHER(atomicExpr);
REGISTER_MATCHER(atomicType);
REGISTER_MATCHER(autoType);
REGISTER_MATCHER(binaryOperator);
REGISTER_MATCHER(binaryConditionalOperator);
REGISTER_MATCHER(blockPointerType);
REGISTER_MATCHER(booleanType);
REGISTER_MATCHER(breakStmt);
Expand Down Expand Up @@ -161,6 +164,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(declStmt);
REGISTER_MATCHER(defaultStmt);
REGISTER_MATCHER(dependentSizedArrayType);
REGISTER_MATCHER(designatedInitExpr);
REGISTER_MATCHER(designatorCountIs);
REGISTER_MATCHER(doStmt);
REGISTER_MATCHER(eachOf);
REGISTER_MATCHER(elaboratedType);
Expand Down Expand Up @@ -245,6 +250,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasSizeExpr);
REGISTER_MATCHER(hasSourceExpression);
REGISTER_MATCHER(hasStaticStorageDuration);
REGISTER_MATCHER(hasSyntacticForm);
REGISTER_MATCHER(hasTargetDecl);
REGISTER_MATCHER(hasTemplateArgument);
REGISTER_MATCHER(hasThen);
Expand All @@ -259,6 +265,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(ignoringParenCasts);
REGISTER_MATCHER(ignoringParenImpCasts);
REGISTER_MATCHER(implicitCastExpr);
REGISTER_MATCHER(implicitValueInitExpr);
REGISTER_MATCHER(incompleteArrayType);
REGISTER_MATCHER(initListExpr);
REGISTER_MATCHER(injectedClassNameType);
Expand Down Expand Up @@ -312,6 +319,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isVirtualAsWritten);
REGISTER_MATCHER(isVolatileQualified);
REGISTER_MATCHER(isWritten);
REGISTER_MATCHER(labelDecl);
REGISTER_MATCHER(labelStmt);
REGISTER_MATCHER(lambdaExpr);
REGISTER_MATCHER(lValueReferenceType);
Expand All @@ -336,12 +344,15 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(objcObjectPointerType);
REGISTER_MATCHER(on);
REGISTER_MATCHER(onImplicitObjectArgument);
REGISTER_MATCHER(opaqueValueExpr);
REGISTER_MATCHER(parameterCountIs);
REGISTER_MATCHER(parenExpr);
REGISTER_MATCHER(parenListExpr);
REGISTER_MATCHER(parenType);
REGISTER_MATCHER(parmVarDecl);
REGISTER_MATCHER(pointee);
REGISTER_MATCHER(pointerType);
REGISTER_MATCHER(predefinedExpr);
REGISTER_MATCHER(qualType);
REGISTER_MATCHER(realFloatingPointType);
REGISTER_MATCHER(recordDecl);
Expand All @@ -350,6 +361,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(refersToDeclaration);
REGISTER_MATCHER(refersToIntegralType);
REGISTER_MATCHER(refersToType);
REGISTER_MATCHER(requiresZeroInitialization);
REGISTER_MATCHER(returns);
REGISTER_MATCHER(returnStmt);
REGISTER_MATCHER(rValueReferenceType);
Expand All @@ -360,6 +372,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(statementCountIs);
REGISTER_MATCHER(staticAssertDecl);
REGISTER_MATCHER(stmt);
REGISTER_MATCHER(stmtExpr);
REGISTER_MATCHER(stringLiteral);
REGISTER_MATCHER(substNonTypeTemplateParmExpr);
REGISTER_MATCHER(substTemplateTypeParmType);
Expand Down
19 changes: 19 additions & 0 deletions clang/unittests/AST/MatchVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class MatchVerifier : public MatchFinder::MatchCallback {
std::vector<std::string>& Args,
Language L);

template <typename MatcherType>
testing::AssertionResult match(const Decl *D, const MatcherType &AMatcher);

protected:
void run(const MatchFinder::MatchResult &Result) override;
virtual void verify(const MatchFinder::MatchResult &Result,
Expand Down Expand Up @@ -127,6 +130,22 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
return testing::AssertionSuccess();
}

/// \brief Runs a matcher over some AST, and returns the result of the
/// verifier for the matched node.
template <typename NodeType> template <typename MatcherType>
testing::AssertionResult MatchVerifier<NodeType>::match(
const Decl *D, const MatcherType &AMatcher) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);

setFailure("Could not find match");
Finder.match(*D, D->getASTContext());

if (!Verified)
return testing::AssertionFailure() << VerifyResult;
return testing::AssertionSuccess();
}

template <typename NodeType>
void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
Expand Down
105 changes: 104 additions & 1 deletion clang/unittests/ASTMatchers/ASTMatchersTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,12 @@ TEST(Matcher, FlowControl) {
EXPECT_TRUE(matches("void f() { while(true) { continue; } }",
continueStmt()));
EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt()));
EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", labelStmt()));
EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}",
labelStmt(
hasDeclaration(
labelDecl(hasName("FOO"))))));
EXPECT_TRUE(matches("void f() { FOO: ; void *ptr = &&FOO; goto *ptr; }",
addrLabelExpr()));
EXPECT_TRUE(matches("void f() { return; }", returnStmt()));
}

Expand Down Expand Up @@ -2527,6 +2532,82 @@ TEST(Matcher, GNUNullExpr) {
EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
}

TEST(Matcher, AtomicExpr) {
EXPECT_TRUE(matches("void foo() { int *ptr; __atomic_load_n(ptr, 1); }",
atomicExpr()));
}

TEST(Matcher, Initializers) {
const char *ToMatch = "void foo() { struct point { double x; double y; };"
" struct point ptarray[10] = "
" { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }";
EXPECT_TRUE(matchesConditionally(
ToMatch,
initListExpr(
has(
cxxConstructExpr(
requiresZeroInitialization())),
has(
initListExpr(
hasType(asString("struct point")),
has(floatLiteral(equals(1.0))),
has(implicitValueInitExpr(
hasType(asString("double")))))),
has(
initListExpr(
hasType(asString("struct point")),
has(floatLiteral(equals(2.0))),
has(floatLiteral(equals(1.0)))))
), true, "-std=gnu++98"));

EXPECT_TRUE(matchesC99(ToMatch,
initListExpr(
hasSyntacticForm(
initListExpr(
has(
designatedInitExpr(
designatorCountIs(2),
has(floatLiteral(
equals(1.0))),
has(integerLiteral(
equals(2))))),
has(
designatedInitExpr(
designatorCountIs(2),
has(floatLiteral(
equals(2.0))),
has(integerLiteral(
equals(2))))),
has(
designatedInitExpr(
designatorCountIs(2),
has(floatLiteral(
equals(1.0))),
has(integerLiteral(
equals(0)))))
)))));
}

TEST(Matcher, ParenListExpr) {
EXPECT_TRUE(
matches(
" template<typename T> class foo { void bar() { foo X(*this); } }; ",
varDecl(hasInitializer(parenListExpr(has(unaryOperator()))))));
}

TEST(Matcher, StmtExpr) {
EXPECT_TRUE(matches("void declToImport() { int C = ({int X=4; X;}); }",
varDecl(hasInitializer(stmtExpr()))));
}

TEST(Matcher, ImportPredefinedExpr) {
// __func__ expands as StringLiteral("foo")
EXPECT_TRUE(matches("void foo() { __func__; }",
predefinedExpr(
hasType(asString("const char [4]")),
has(stringLiteral()))));
}

TEST(Matcher, AsmStatement) {
EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
}
Expand Down Expand Up @@ -2750,6 +2831,28 @@ TEST(Matcher, ConditionalOperator) {
EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse));
EXPECT_TRUE(
notMatches("void x() { true ? false : true; }", ConditionalFalse));

EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse));
EXPECT_TRUE(
notMatches("void x() { true ? false : true; }", ConditionalFalse));
}

TEST(Matcher, BinaryConditionalOperator) {
StatementMatcher AlwaysOne = binaryConditionalOperator(
hasCondition(implicitCastExpr(
has(
opaqueValueExpr(
hasSourceExpression((integerLiteral(equals(1)))))))),
hasFalseExpression(integerLiteral(equals(0))));

EXPECT_TRUE(matches("void x() { 1 ?: 0; }", AlwaysOne));

StatementMatcher FourNotFive = binaryConditionalOperator(
hasTrueExpression(opaqueValueExpr(
hasSourceExpression((integerLiteral(equals(4)))))),
hasFalseExpression(integerLiteral(equals(5))));

EXPECT_TRUE(matches("void x() { 4 ?: 5; }", FourNotFive));
}

TEST(ArraySubscriptMatchers, ArraySubscripts) {
Expand Down
7 changes: 7 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ testing::AssertionResult matchesC(const std::string &Code, const T &AMatcher) {
"input.c");
}

template <typename T>
testing::AssertionResult matchesC99(const std::string &Code,
const T &AMatcher) {
return matchesConditionally(Code, AMatcher, true, "-std=c99",
FileContentMappings(), "input.c");
}

template <typename T>
testing::AssertionResult notMatchesC(const std::string &Code,
const T &AMatcher) {
Expand Down