blob: 965a4bc3083386133c2511fc129d4ce1deb66a09 [file] [log] [blame]
Artem Dergachevda9e7182017-04-06 14:34:07 +00001//===- unittests/Analysis/CloneDetectionTest.cpp - Clone detection tests --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/RecursiveASTVisitor.h"
11#include "clang/Analysis/CloneDetection.h"
12#include "clang/Tooling/Tooling.h"
13#include "gtest/gtest.h"
14
15namespace clang {
16namespace analysis {
17namespace {
18
19class CloneDetectionVisitor
20 : public RecursiveASTVisitor<CloneDetectionVisitor> {
21
22 CloneDetector &Detector;
23
24public:
25 explicit CloneDetectionVisitor(CloneDetector &D) : Detector(D) {}
26
27 bool VisitFunctionDecl(FunctionDecl *D) {
28 Detector.analyzeCodeBody(D);
29 return true;
30 }
31};
32
33/// Example constraint for testing purposes.
34/// Filters out all statements that are in a function which name starts with
35/// "bar".
36class NoBarFunctionConstraint {
37public:
38 void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
39 CloneConstraint::splitCloneGroups(
40 CloneGroups, [](const StmtSequence &A, const StmtSequence &B) {
41 // Check if one of the sequences is in a function which name starts
42 // with "bar".
43 for (const StmtSequence &Arg : {A, B}) {
44 if (const auto *D =
45 dyn_cast<const FunctionDecl>(Arg.getContainingDecl())) {
46 if (D->getNameAsString().find("bar") == 0)
47 return false;
48 }
49 }
50 return true;
51 });
52 }
53};
54
55TEST(CloneDetector, FilterFunctionsByName) {
56 auto ASTUnit =
57 clang::tooling::buildASTFromCode("void foo1(int &a1) { a1++; }\n"
58 "void foo2(int &a2) { a2++; }\n"
59 "void bar1(int &a3) { a3++; }\n"
60 "void bar2(int &a4) { a4++; }\n");
61 auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
62
63 CloneDetector Detector;
64 // Push all the function bodies into the detector.
65 CloneDetectionVisitor Visitor(Detector);
66 Visitor.TraverseTranslationUnitDecl(TU);
67
68 // Find clones with the usual settings, but but we want to filter out
69 // all statements from functions which names start with "bar".
70 std::vector<CloneDetector::CloneGroup> CloneGroups;
71 Detector.findClones(CloneGroups, NoBarFunctionConstraint(),
Raphael Isemann70686a12017-08-31 07:10:46 +000072 RecursiveCloneTypeIIHashConstraint(),
Artem Dergachevda9e7182017-04-06 14:34:07 +000073 MinComplexityConstraint(2), MinGroupSizeConstraint(2),
Raphael Isemann70686a12017-08-31 07:10:46 +000074 RecursiveCloneTypeIIVerifyConstraint(),
Artem Dergachevda9e7182017-04-06 14:34:07 +000075 OnlyLargestCloneConstraint());
76
77 ASSERT_EQ(CloneGroups.size(), 1u);
78 ASSERT_EQ(CloneGroups.front().size(), 2u);
79
80 for (auto &Clone : CloneGroups.front()) {
81 const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
82 ASSERT_TRUE(ND != nullptr);
83 // Check that no function name starting with "bar" is in the results...
84 ASSERT_TRUE(ND->getNameAsString().find("bar") != 0);
85 }
86
87 // Retry above's example without the filter...
88 CloneGroups.clear();
89
Raphael Isemann70686a12017-08-31 07:10:46 +000090 Detector.findClones(CloneGroups, RecursiveCloneTypeIIHashConstraint(),
Artem Dergachevda9e7182017-04-06 14:34:07 +000091 MinComplexityConstraint(2), MinGroupSizeConstraint(2),
Raphael Isemann70686a12017-08-31 07:10:46 +000092 RecursiveCloneTypeIIVerifyConstraint(),
Artem Dergachevda9e7182017-04-06 14:34:07 +000093 OnlyLargestCloneConstraint());
94 ASSERT_EQ(CloneGroups.size(), 1u);
95 ASSERT_EQ(CloneGroups.front().size(), 4u);
96
97 // Count how many functions with the bar prefix we have in the results.
98 int FoundFunctionsWithBarPrefix = 0;
99 for (auto &Clone : CloneGroups.front()) {
100 const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
101 ASSERT_TRUE(ND != nullptr);
102 // This time check that we picked up the bar functions from above
103 if (ND->getNameAsString().find("bar") == 0) {
104 FoundFunctionsWithBarPrefix++;
105 }
106 }
107 // We should have found the two functions bar1 and bar2.
108 ASSERT_EQ(FoundFunctionsWithBarPrefix, 2);
109}
110} // namespace
111} // namespace analysis
112} // namespace clang