tbourvon created this revision.
tbourvon added a reviewer: lebedev.ri.
tbourvon added a project: clang-tools-extra.
Herald added subscribers: hintonda, xazax.hun, mgorny.
This adds a utility matcher (which is placed in `util/Matchers.h`, because it
uses functions from `ASTMatchFinder.h` which cannot be used from
`ASTMatchers.h`) used by https://reviews.llvm.org/D37014).
https://reviews.llvm.org/D42624
Files:
clang-tidy/utils/Matchers.h
unittests/clang-tidy/CMakeLists.txt
unittests/clang-tidy/MatchersUtilsTest.cpp
Index: unittests/clang-tidy/MatchersUtilsTest.cpp
===================================================================
--- /dev/null
+++ unittests/clang-tidy/MatchersUtilsTest.cpp
@@ -0,0 +1,25 @@
+#include "../../../unittests/ASTMatchers/ASTMatchersTest.h"
+#include "utils/Matchers.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+using namespace ast_matchers;
+using namespace matchers;
+
+TEST(StatementMatcher, HasSuccessor) {
+ StatementMatcher DeclHasSuccessorReturnStmt =
+ declStmt(hasSuccessor(returnStmt()));
+
+ EXPECT_TRUE(matches(
+ "void foo() { int bar; return; }",
+ DeclHasSuccessorReturnStmt));
+ EXPECT_TRUE(notMatches(
+ "void foo() { int bar; bar++; return; }",
+ DeclHasSuccessorReturnStmt));
+}
+
+}
+}
+}
Index: unittests/clang-tidy/CMakeLists.txt
===================================================================
--- unittests/clang-tidy/CMakeLists.txt
+++ unittests/clang-tidy/CMakeLists.txt
@@ -12,6 +12,7 @@
IncludeInserterTest.cpp
GoogleModuleTest.cpp
LLVMModuleTest.cpp
+ MatchersUtilsTest.cpp
NamespaceAliaserTest.cpp
ObjCModuleTest.cpp
OverlappingReplacementsTest.cpp
Index: clang-tidy/utils/Matchers.h
===================================================================
--- clang-tidy/utils/Matchers.h
+++ clang-tidy/utils/Matchers.h
@@ -12,6 +12,8 @@
#include "TypeTraits.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CFG.h"
namespace clang {
namespace tidy {
@@ -48,6 +50,67 @@
return referenceType(pointee(qualType(isConstQualified())));
}
+// Matches the next statement within the parent statement sequence.
+AST_MATCHER_P(Stmt, hasSuccessor,
+ ast_matchers::internal::Matcher<Stmt>, InnerMatcher) {
+ using namespace ast_matchers;
+
+ // We get the first parent, making sure that we're not in a case statement
+ // not in a compound statement directly inside a switch, because this causes
+ // the buildCFG call to crash.
+ auto Parent = selectFirst<Stmt>(
+ "parent",
+ match(
+ stmt(hasAncestor(stmt(
+ unless(caseStmt()),
+ unless(compoundStmt(hasParent(switchStmt()))),
+ stmt().bind("parent")))),
+ Node, Finder->getASTContext()));
+
+ // We build a Control Flow Graph (CFG) from the parent statement.
+ std::unique_ptr<CFG> StatementCFG =
+ CFG::buildCFG(nullptr, const_cast<Stmt*>(Parent), &Finder->getASTContext(),
+ CFG::BuildOptions());
+
+ if (!StatementCFG) {
+ return false;
+ }
+
+ // We iterate through all the CFGBlocks, which basically means that we go over
+ // all the possible branches of the code and therefore cover all statements.
+ for (auto& Block : *StatementCFG) {
+ if (!Block) {
+ continue;
+ }
+
+ // We iterate through all the statements of the block.
+ bool ReturnNextStmt = false;
+ for (auto& BlockItem : *Block) {
+ Optional<CFGStmt> CFGStatement = BlockItem.getAs<CFGStmt>();
+ if (!CFGStatement) {
+ if (ReturnNextStmt) {
+ return false;
+ }
+
+ continue;
+ }
+
+ // If we found the next statement, we apply the inner matcher and return
+ // the result.
+ if (ReturnNextStmt) {
+ return InnerMatcher.matches(*CFGStatement->getStmt(), Finder, Builder);
+ }
+
+ if (CFGStatement->getStmt() == &Node) {
+ ReturnNextStmt = true;
+ }
+ }
+ }
+
+ // If we didn't find a successor, we just return false.
+ return false;
+}
+
} // namespace matchers
} // namespace tidy
} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits