summaryrefslogtreecommitdiff
path: root/unittests/Analysis/CloneDetectionTest.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
commit7442d6faa2719e4e7d33a7021c406c5a4facd74d (patch)
treec72b9241553fc9966179aba84f90f17bfa9235c3 /unittests/Analysis/CloneDetectionTest.cpp
parentb52119637f743680a99710ce5fdb6646da2772af (diff)
Diffstat (limited to 'unittests/Analysis/CloneDetectionTest.cpp')
-rw-r--r--unittests/Analysis/CloneDetectionTest.cpp110
1 files changed, 110 insertions, 0 deletions
diff --git a/unittests/Analysis/CloneDetectionTest.cpp b/unittests/Analysis/CloneDetectionTest.cpp
new file mode 100644
index 0000000000000..6d8ce3495fa8a
--- /dev/null
+++ b/unittests/Analysis/CloneDetectionTest.cpp
@@ -0,0 +1,110 @@
+//===- unittests/Analysis/CloneDetectionTest.cpp - Clone detection tests --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/CloneDetection.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace analysis {
+namespace {
+
+class CloneDetectionVisitor
+ : public RecursiveASTVisitor<CloneDetectionVisitor> {
+
+ CloneDetector &Detector;
+
+public:
+ explicit CloneDetectionVisitor(CloneDetector &D) : Detector(D) {}
+
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ Detector.analyzeCodeBody(D);
+ return true;
+ }
+};
+
+/// Example constraint for testing purposes.
+/// Filters out all statements that are in a function which name starts with
+/// "bar".
+class NoBarFunctionConstraint {
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::splitCloneGroups(
+ CloneGroups, [](const StmtSequence &A, const StmtSequence &B) {
+ // Check if one of the sequences is in a function which name starts
+ // with "bar".
+ for (const StmtSequence &Arg : {A, B}) {
+ if (const auto *D =
+ dyn_cast<const FunctionDecl>(Arg.getContainingDecl())) {
+ if (D->getNameAsString().find("bar") == 0)
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+};
+
+TEST(CloneDetector, FilterFunctionsByName) {
+ auto ASTUnit =
+ clang::tooling::buildASTFromCode("void foo1(int &a1) { a1++; }\n"
+ "void foo2(int &a2) { a2++; }\n"
+ "void bar1(int &a3) { a3++; }\n"
+ "void bar2(int &a4) { a4++; }\n");
+ auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+
+ CloneDetector Detector;
+ // Push all the function bodies into the detector.
+ CloneDetectionVisitor Visitor(Detector);
+ Visitor.TraverseTranslationUnitDecl(TU);
+
+ // Find clones with the usual settings, but but we want to filter out
+ // all statements from functions which names start with "bar".
+ std::vector<CloneDetector::CloneGroup> CloneGroups;
+ Detector.findClones(CloneGroups, NoBarFunctionConstraint(),
+ RecursiveCloneTypeIIConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ OnlyLargestCloneConstraint());
+
+ ASSERT_EQ(CloneGroups.size(), 1u);
+ ASSERT_EQ(CloneGroups.front().size(), 2u);
+
+ for (auto &Clone : CloneGroups.front()) {
+ const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
+ ASSERT_TRUE(ND != nullptr);
+ // Check that no function name starting with "bar" is in the results...
+ ASSERT_TRUE(ND->getNameAsString().find("bar") != 0);
+ }
+
+ // Retry above's example without the filter...
+ CloneGroups.clear();
+
+ Detector.findClones(CloneGroups, RecursiveCloneTypeIIConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ OnlyLargestCloneConstraint());
+ ASSERT_EQ(CloneGroups.size(), 1u);
+ ASSERT_EQ(CloneGroups.front().size(), 4u);
+
+ // Count how many functions with the bar prefix we have in the results.
+ int FoundFunctionsWithBarPrefix = 0;
+ for (auto &Clone : CloneGroups.front()) {
+ const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
+ ASSERT_TRUE(ND != nullptr);
+ // This time check that we picked up the bar functions from above
+ if (ND->getNameAsString().find("bar") == 0) {
+ FoundFunctionsWithBarPrefix++;
+ }
+ }
+ // We should have found the two functions bar1 and bar2.
+ ASSERT_EQ(FoundFunctionsWithBarPrefix, 2);
+}
+} // namespace
+} // namespace analysis
+} // namespace clang