diff options
author | Sam Panzer <espanz@gmail.com> | 2012-08-16 17:20:59 +0000 |
---|---|---|
committer | Sam Panzer <espanz@gmail.com> | 2012-08-16 17:20:59 +0000 |
commit | 425f41b370a8795fbca9ffc3b35e9b0ccbb15d97 (patch) | |
tree | 620f7af001819b6f38bf8d95e79ffdedcb1d8520 | |
parent | f64c11815e68f025737dc41d8d94e31e1426274d (diff) |
Matchers related to DeclStmt for matching the count of declarations, a particular declaration within the statement, and single-Decl DeclStmts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162027 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 54 | ||||
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 34 |
2 files changed, 88 insertions, 0 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index af1689dbee..33ef3dc8d6 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -50,6 +50,7 @@ #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Regex.h" +#include <iterator> namespace clang { namespace ast_matchers { @@ -1275,6 +1276,21 @@ AST_MATCHER_P(DeclRefExpr, throughUsingDecl, return false; } +/// \brief Matches the Decl of a DeclStmt which has a single declaration. +/// +/// Given +/// int a, b; +/// int c; +/// declarationStatement(hasSingleDecl(anything())) +/// matches 'int c;' but not 'int a, b;'. +AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) { + if (Node.isSingleDecl()) { + const Decl *FoundDecl = Node.getSingleDecl(); + return InnerMatcher.matches(*FoundDecl, Finder, Builder); + } + return false; +} + /// \brief Matches a variable declaration that has an initializer expression /// that matches the given matcher. /// @@ -1320,6 +1336,44 @@ AST_POLYMORPHIC_MATCHER_P2( *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// \brief Matches declaration statements that contain a specific number of +/// declarations. +/// +/// Example: Given +/// int a, b; +/// int c; +/// int d = 2, e; +/// declCountIs(2) +/// matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'. +AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) { + return std::distance(Node.decl_begin(), Node.decl_end()) == N; +} + +/// \brief Matches the n'th declaration of a declaration statement. +/// +/// Note that this does not work for global declarations because the AST +/// breaks up multiple-declaration DeclStmt's into multiple single-declaration +/// DeclStmt's. +/// Example: Given non-global declarations +/// int a, b = 0; +/// int c; +/// int d = 2, e; +/// declarationStatement(containsDeclaration( +/// 0, variable(hasInitializer(anything())))) +/// matches only 'int d = 2, e;', and +/// declarationStatement(containsDeclaration(1, variable())) +/// matches 'int a, b = 0' as well as 'int d = 2, e;' +/// but 'int c;' is not matched. +AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N, + internal::Matcher<Decl>, InnerMatcher) { + const unsigned NumDecls = std::distance(Node.decl_begin(), Node.decl_end()); + if (N >= NumDecls) + return false; + DeclStmt::const_decl_iterator Iterator = Node.decl_begin(); + std::advance(Iterator, N); + return InnerMatcher.matches(**Iterator, Finder, Builder); +} + /// \brief Matches a constructor initializer. /// /// Given diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index bf80ad4a64..adf0e9479f 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -2377,6 +2377,40 @@ TEST(UsingDeclaration, ThroughUsingDeclaration) { declarationReference(throughUsingDecl(anything())))); } +TEST(SingleDecl, IsSingleDecl) { + StatementMatcher SingleDeclStmt = + declarationStatement(hasSingleDecl(variable(hasInitializer(anything())))); + EXPECT_TRUE(matches("void f() {int a = 4;}", SingleDeclStmt)); + EXPECT_TRUE(notMatches("void f() {int a;}", SingleDeclStmt)); + EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}", + SingleDeclStmt)); +} + +TEST(DeclStmt, ContainsDeclaration) { + DeclarationMatcher MatchesInit = variable(hasInitializer(anything())); + + EXPECT_TRUE(matches("void f() {int a = 4;}", + declarationStatement(containsDeclaration(0, + MatchesInit)))); + EXPECT_TRUE(matches("void f() {int a = 4, b = 3;}", + declarationStatement(containsDeclaration(0, MatchesInit), + containsDeclaration(1, + MatchesInit)))); + unsigned WrongIndex = 42; + EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}", + declarationStatement(containsDeclaration(WrongIndex, + MatchesInit)))); +} + +TEST(DeclCount, DeclCountIsCorrect) { + EXPECT_TRUE(matches("void f() {int i,j;}", + declarationStatement(declCountIs(2)))); + EXPECT_TRUE(notMatches("void f() {int i,j; int k;}", + declarationStatement(declCountIs(3)))); + EXPECT_TRUE(notMatches("void f() {int i,j, k, l;}", + declarationStatement(declCountIs(3)))); +} + TEST(While, MatchesWhileLoops) { EXPECT_TRUE(notMatches("void x() {}", whileStmt())); EXPECT_TRUE(matches("void x() { while(true); }", whileStmt())); |