CloneDetection.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. //===--- CloneDetection.cpp - Finds code clones in an AST -------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// This file implements classes for searching and analyzing source code clones.
  10. ///
  11. //===----------------------------------------------------------------------===//
  12. #include "clang/Analysis/CloneDetection.h"
  13. #include "clang/AST/Attr.h"
  14. #include "clang/AST/DataCollection.h"
  15. #include "clang/AST/DeclTemplate.h"
  16. #include "clang/Basic/SourceManager.h"
  17. #include "llvm/Support/MD5.h"
  18. #include "llvm/Support/Path.h"
  19. using namespace clang;
  20. StmtSequence::StmtSequence(const CompoundStmt *Stmt, const Decl *D,
  21. unsigned StartIndex, unsigned EndIndex)
  22. : S(Stmt), D(D), StartIndex(StartIndex), EndIndex(EndIndex) {
  23. assert(Stmt && "Stmt must not be a nullptr");
  24. assert(StartIndex < EndIndex && "Given array should not be empty");
  25. assert(EndIndex <= Stmt->size() && "Given array too big for this Stmt");
  26. }
  27. StmtSequence::StmtSequence(const Stmt *Stmt, const Decl *D)
  28. : S(Stmt), D(D), StartIndex(0), EndIndex(0) {}
  29. StmtSequence::StmtSequence()
  30. : S(nullptr), D(nullptr), StartIndex(0), EndIndex(0) {}
  31. bool StmtSequence::contains(const StmtSequence &Other) const {
  32. // If both sequences reside in different declarations, they can never contain
  33. // each other.
  34. if (D != Other.D)
  35. return false;
  36. const SourceManager &SM = getASTContext().getSourceManager();
  37. // Otherwise check if the start and end locations of the current sequence
  38. // surround the other sequence.
  39. bool StartIsInBounds =
  40. SM.isBeforeInTranslationUnit(getBeginLoc(), Other.getBeginLoc()) ||
  41. getBeginLoc() == Other.getBeginLoc();
  42. if (!StartIsInBounds)
  43. return false;
  44. bool EndIsInBounds =
  45. SM.isBeforeInTranslationUnit(Other.getEndLoc(), getEndLoc()) ||
  46. Other.getEndLoc() == getEndLoc();
  47. return EndIsInBounds;
  48. }
  49. StmtSequence::iterator StmtSequence::begin() const {
  50. if (!holdsSequence()) {
  51. return &S;
  52. }
  53. auto CS = cast<CompoundStmt>(S);
  54. return CS->body_begin() + StartIndex;
  55. }
  56. StmtSequence::iterator StmtSequence::end() const {
  57. if (!holdsSequence()) {
  58. return reinterpret_cast<StmtSequence::iterator>(&S) + 1;
  59. }
  60. auto CS = cast<CompoundStmt>(S);
  61. return CS->body_begin() + EndIndex;
  62. }
  63. ASTContext &StmtSequence::getASTContext() const {
  64. assert(D);
  65. return D->getASTContext();
  66. }
  67. SourceLocation StmtSequence::getBeginLoc() const {
  68. return front()->getBeginLoc();
  69. }
  70. SourceLocation StmtSequence::getEndLoc() const { return back()->getEndLoc(); }
  71. SourceRange StmtSequence::getSourceRange() const {
  72. return SourceRange(getBeginLoc(), getEndLoc());
  73. }
  74. void CloneDetector::analyzeCodeBody(const Decl *D) {
  75. assert(D);
  76. assert(D->hasBody());
  77. Sequences.push_back(StmtSequence(D->getBody(), D));
  78. }
  79. /// Returns true if and only if \p Stmt contains at least one other
  80. /// sequence in the \p Group.
  81. static bool containsAnyInGroup(StmtSequence &Seq,
  82. CloneDetector::CloneGroup &Group) {
  83. for (StmtSequence &GroupSeq : Group) {
  84. if (Seq.contains(GroupSeq))
  85. return true;
  86. }
  87. return false;
  88. }
  89. /// Returns true if and only if all sequences in \p OtherGroup are
  90. /// contained by a sequence in \p Group.
  91. static bool containsGroup(CloneDetector::CloneGroup &Group,
  92. CloneDetector::CloneGroup &OtherGroup) {
  93. // We have less sequences in the current group than we have in the other,
  94. // so we will never fulfill the requirement for returning true. This is only
  95. // possible because we know that a sequence in Group can contain at most
  96. // one sequence in OtherGroup.
  97. if (Group.size() < OtherGroup.size())
  98. return false;
  99. for (StmtSequence &Stmt : Group) {
  100. if (!containsAnyInGroup(Stmt, OtherGroup))
  101. return false;
  102. }
  103. return true;
  104. }
  105. void OnlyLargestCloneConstraint::constrain(
  106. std::vector<CloneDetector::CloneGroup> &Result) {
  107. std::vector<unsigned> IndexesToRemove;
  108. // Compare every group in the result with the rest. If one groups contains
  109. // another group, we only need to return the bigger group.
  110. // Note: This doesn't scale well, so if possible avoid calling any heavy
  111. // function from this loop to minimize the performance impact.
  112. for (unsigned i = 0; i < Result.size(); ++i) {
  113. for (unsigned j = 0; j < Result.size(); ++j) {
  114. // Don't compare a group with itself.
  115. if (i == j)
  116. continue;
  117. if (containsGroup(Result[j], Result[i])) {
  118. IndexesToRemove.push_back(i);
  119. break;
  120. }
  121. }
  122. }
  123. // Erasing a list of indexes from the vector should be done with decreasing
  124. // indexes. As IndexesToRemove is constructed with increasing values, we just
  125. // reverse iterate over it to get the desired order.
  126. for (unsigned I : llvm::reverse(IndexesToRemove))
  127. Result.erase(Result.begin() + I);
  128. }
  129. bool FilenamePatternConstraint::isAutoGenerated(
  130. const CloneDetector::CloneGroup &Group) {
  131. if (IgnoredFilesPattern.empty() || Group.empty() ||
  132. !IgnoredFilesRegex->isValid())
  133. return false;
  134. for (const StmtSequence &S : Group) {
  135. const SourceManager &SM = S.getASTContext().getSourceManager();
  136. StringRef Filename = llvm::sys::path::filename(
  137. SM.getFilename(S.getContainingDecl()->getLocation()));
  138. if (IgnoredFilesRegex->match(Filename))
  139. return true;
  140. }
  141. return false;
  142. }
  143. /// This class defines what a type II code clone is: If it collects for two
  144. /// statements the same data, then those two statements are considered to be
  145. /// clones of each other.
  146. ///
  147. /// All collected data is forwarded to the given data consumer of the type T.
  148. /// The data consumer class needs to provide a member method with the signature:
  149. /// update(StringRef Str)
  150. namespace {
  151. template <class T>
  152. class CloneTypeIIStmtDataCollector
  153. : public ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>> {
  154. ASTContext &Context;
  155. /// The data sink to which all data is forwarded.
  156. T &DataConsumer;
  157. template <class Ty> void addData(const Ty &Data) {
  158. data_collection::addDataToConsumer(DataConsumer, Data);
  159. }
  160. public:
  161. CloneTypeIIStmtDataCollector(const Stmt *S, ASTContext &Context,
  162. T &DataConsumer)
  163. : Context(Context), DataConsumer(DataConsumer) {
  164. this->Visit(S);
  165. }
  166. // Define a visit method for each class to collect data and subsequently visit
  167. // all parent classes. This uses a template so that custom visit methods by us
  168. // take precedence.
  169. #define DEF_ADD_DATA(CLASS, CODE) \
  170. template <class = void> void Visit##CLASS(const CLASS *S) { \
  171. CODE; \
  172. ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \
  173. }
  174. #include "clang/AST/StmtDataCollectors.inc"
  175. // Type II clones ignore variable names and literals, so let's skip them.
  176. #define SKIP(CLASS) \
  177. void Visit##CLASS(const CLASS *S) { \
  178. ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \
  179. }
  180. SKIP(DeclRefExpr)
  181. SKIP(MemberExpr)
  182. SKIP(IntegerLiteral)
  183. SKIP(FloatingLiteral)
  184. SKIP(StringLiteral)
  185. SKIP(CXXBoolLiteralExpr)
  186. SKIP(CharacterLiteral)
  187. #undef SKIP
  188. };
  189. } // end anonymous namespace
  190. static size_t createHash(llvm::MD5 &Hash) {
  191. size_t HashCode;
  192. // Create the final hash code for the current Stmt.
  193. llvm::MD5::MD5Result HashResult;
  194. Hash.final(HashResult);
  195. // Copy as much as possible of the generated hash code to the Stmt's hash
  196. // code.
  197. std::memcpy(&HashCode, &HashResult,
  198. std::min(sizeof(HashCode), sizeof(HashResult)));
  199. return HashCode;
  200. }
  201. /// Generates and saves a hash code for the given Stmt.
  202. /// \param S The given Stmt.
  203. /// \param D The Decl containing S.
  204. /// \param StmtsByHash Output parameter that will contain the hash codes for
  205. /// each StmtSequence in the given Stmt.
  206. /// \return The hash code of the given Stmt.
  207. ///
  208. /// If the given Stmt is a CompoundStmt, this method will also generate
  209. /// hashes for all possible StmtSequences in the children of this Stmt.
  210. static size_t
  211. saveHash(const Stmt *S, const Decl *D,
  212. std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash) {
  213. llvm::MD5 Hash;
  214. ASTContext &Context = D->getASTContext();
  215. CloneTypeIIStmtDataCollector<llvm::MD5>(S, Context, Hash);
  216. auto CS = dyn_cast<CompoundStmt>(S);
  217. SmallVector<size_t, 8> ChildHashes;
  218. for (const Stmt *Child : S->children()) {
  219. if (Child == nullptr) {
  220. ChildHashes.push_back(0);
  221. continue;
  222. }
  223. size_t ChildHash = saveHash(Child, D, StmtsByHash);
  224. Hash.update(
  225. StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
  226. ChildHashes.push_back(ChildHash);
  227. }
  228. if (CS) {
  229. // If we're in a CompoundStmt, we hash all possible combinations of child
  230. // statements to find clones in those subsequences.
  231. // We first go through every possible starting position of a subsequence.
  232. for (unsigned Pos = 0; Pos < CS->size(); ++Pos) {
  233. // Then we try all possible lengths this subsequence could have and
  234. // reuse the same hash object to make sure we only hash every child
  235. // hash exactly once.
  236. llvm::MD5 Hash;
  237. for (unsigned Length = 1; Length <= CS->size() - Pos; ++Length) {
  238. // Grab the current child hash and put it into our hash. We do
  239. // -1 on the index because we start counting the length at 1.
  240. size_t ChildHash = ChildHashes[Pos + Length - 1];
  241. Hash.update(
  242. StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
  243. // If we have at least two elements in our subsequence, we can start
  244. // saving it.
  245. if (Length > 1) {
  246. llvm::MD5 SubHash = Hash;
  247. StmtsByHash.push_back(std::make_pair(
  248. createHash(SubHash), StmtSequence(CS, D, Pos, Pos + Length)));
  249. }
  250. }
  251. }
  252. }
  253. size_t HashCode = createHash(Hash);
  254. StmtsByHash.push_back(std::make_pair(HashCode, StmtSequence(S, D)));
  255. return HashCode;
  256. }
  257. namespace {
  258. /// Wrapper around FoldingSetNodeID that it can be used as the template
  259. /// argument of the StmtDataCollector.
  260. class FoldingSetNodeIDWrapper {
  261. llvm::FoldingSetNodeID &FS;
  262. public:
  263. FoldingSetNodeIDWrapper(llvm::FoldingSetNodeID &FS) : FS(FS) {}
  264. void update(StringRef Str) { FS.AddString(Str); }
  265. };
  266. } // end anonymous namespace
  267. /// Writes the relevant data from all statements and child statements
  268. /// in the given StmtSequence into the given FoldingSetNodeID.
  269. static void CollectStmtSequenceData(const StmtSequence &Sequence,
  270. FoldingSetNodeIDWrapper &OutputData) {
  271. for (const Stmt *S : Sequence) {
  272. CloneTypeIIStmtDataCollector<FoldingSetNodeIDWrapper>(
  273. S, Sequence.getASTContext(), OutputData);
  274. for (const Stmt *Child : S->children()) {
  275. if (!Child)
  276. continue;
  277. CollectStmtSequenceData(StmtSequence(Child, Sequence.getContainingDecl()),
  278. OutputData);
  279. }
  280. }
  281. }
  282. /// Returns true if both sequences are clones of each other.
  283. static bool areSequencesClones(const StmtSequence &LHS,
  284. const StmtSequence &RHS) {
  285. // We collect the data from all statements in the sequence as we did before
  286. // when generating a hash value for each sequence. But this time we don't
  287. // hash the collected data and compare the whole data set instead. This
  288. // prevents any false-positives due to hash code collisions.
  289. llvm::FoldingSetNodeID DataLHS, DataRHS;
  290. FoldingSetNodeIDWrapper LHSWrapper(DataLHS);
  291. FoldingSetNodeIDWrapper RHSWrapper(DataRHS);
  292. CollectStmtSequenceData(LHS, LHSWrapper);
  293. CollectStmtSequenceData(RHS, RHSWrapper);
  294. return DataLHS == DataRHS;
  295. }
  296. void RecursiveCloneTypeIIHashConstraint::constrain(
  297. std::vector<CloneDetector::CloneGroup> &Sequences) {
  298. // FIXME: Maybe we can do this in-place and don't need this additional vector.
  299. std::vector<CloneDetector::CloneGroup> Result;
  300. for (CloneDetector::CloneGroup &Group : Sequences) {
  301. // We assume in the following code that the Group is non-empty, so we
  302. // skip all empty groups.
  303. if (Group.empty())
  304. continue;
  305. std::vector<std::pair<size_t, StmtSequence>> StmtsByHash;
  306. // Generate hash codes for all children of S and save them in StmtsByHash.
  307. for (const StmtSequence &S : Group) {
  308. saveHash(S.front(), S.getContainingDecl(), StmtsByHash);
  309. }
  310. // Sort hash_codes in StmtsByHash.
  311. llvm::stable_sort(StmtsByHash, llvm::less_first());
  312. // Check for each StmtSequence if its successor has the same hash value.
  313. // We don't check the last StmtSequence as it has no successor.
  314. // Note: The 'size - 1 ' in the condition is safe because we check for an
  315. // empty Group vector at the beginning of this function.
  316. for (unsigned i = 0; i < StmtsByHash.size() - 1; ++i) {
  317. const auto Current = StmtsByHash[i];
  318. // It's likely that we just found a sequence of StmtSequences that
  319. // represent a CloneGroup, so we create a new group and start checking and
  320. // adding the StmtSequences in this sequence.
  321. CloneDetector::CloneGroup NewGroup;
  322. size_t PrototypeHash = Current.first;
  323. for (; i < StmtsByHash.size(); ++i) {
  324. // A different hash value means we have reached the end of the sequence.
  325. if (PrototypeHash != StmtsByHash[i].first) {
  326. // The current sequence could be the start of a new CloneGroup. So we
  327. // decrement i so that we visit it again in the outer loop.
  328. // Note: i can never be 0 at this point because we are just comparing
  329. // the hash of the Current StmtSequence with itself in the 'if' above.
  330. assert(i != 0);
  331. --i;
  332. break;
  333. }
  334. // Same hash value means we should add the StmtSequence to the current
  335. // group.
  336. NewGroup.push_back(StmtsByHash[i].second);
  337. }
  338. // We created a new clone group with matching hash codes and move it to
  339. // the result vector.
  340. Result.push_back(NewGroup);
  341. }
  342. }
  343. // Sequences is the output parameter, so we copy our result into it.
  344. Sequences = Result;
  345. }
  346. void RecursiveCloneTypeIIVerifyConstraint::constrain(
  347. std::vector<CloneDetector::CloneGroup> &Sequences) {
  348. CloneConstraint::splitCloneGroups(
  349. Sequences, [](const StmtSequence &A, const StmtSequence &B) {
  350. return areSequencesClones(A, B);
  351. });
  352. }
  353. size_t MinComplexityConstraint::calculateStmtComplexity(
  354. const StmtSequence &Seq, std::size_t Limit,
  355. const std::string &ParentMacroStack) {
  356. if (Seq.empty())
  357. return 0;
  358. size_t Complexity = 1;
  359. ASTContext &Context = Seq.getASTContext();
  360. // Look up what macros expanded into the current statement.
  361. std::string MacroStack =
  362. data_collection::getMacroStack(Seq.getBeginLoc(), Context);
  363. // First, check if ParentMacroStack is not empty which means we are currently
  364. // dealing with a parent statement which was expanded from a macro.
  365. // If this parent statement was expanded from the same macros as this
  366. // statement, we reduce the initial complexity of this statement to zero.
  367. // This causes that a group of statements that were generated by a single
  368. // macro expansion will only increase the total complexity by one.
  369. // Note: This is not the final complexity of this statement as we still
  370. // add the complexity of the child statements to the complexity value.
  371. if (!ParentMacroStack.empty() && MacroStack == ParentMacroStack) {
  372. Complexity = 0;
  373. }
  374. // Iterate over the Stmts in the StmtSequence and add their complexity values
  375. // to the current complexity value.
  376. if (Seq.holdsSequence()) {
  377. for (const Stmt *S : Seq) {
  378. Complexity += calculateStmtComplexity(
  379. StmtSequence(S, Seq.getContainingDecl()), Limit, MacroStack);
  380. if (Complexity >= Limit)
  381. return Limit;
  382. }
  383. } else {
  384. for (const Stmt *S : Seq.front()->children()) {
  385. Complexity += calculateStmtComplexity(
  386. StmtSequence(S, Seq.getContainingDecl()), Limit, MacroStack);
  387. if (Complexity >= Limit)
  388. return Limit;
  389. }
  390. }
  391. return Complexity;
  392. }
  393. void MatchingVariablePatternConstraint::constrain(
  394. std::vector<CloneDetector::CloneGroup> &CloneGroups) {
  395. CloneConstraint::splitCloneGroups(
  396. CloneGroups, [](const StmtSequence &A, const StmtSequence &B) {
  397. VariablePattern PatternA(A);
  398. VariablePattern PatternB(B);
  399. return PatternA.countPatternDifferences(PatternB) == 0;
  400. });
  401. }
  402. void CloneConstraint::splitCloneGroups(
  403. std::vector<CloneDetector::CloneGroup> &CloneGroups,
  404. llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)>
  405. Compare) {
  406. std::vector<CloneDetector::CloneGroup> Result;
  407. for (auto &HashGroup : CloneGroups) {
  408. // Contains all indexes in HashGroup that were already added to a
  409. // CloneGroup.
  410. std::vector<char> Indexes;
  411. Indexes.resize(HashGroup.size());
  412. for (unsigned i = 0; i < HashGroup.size(); ++i) {
  413. // Skip indexes that are already part of a CloneGroup.
  414. if (Indexes[i])
  415. continue;
  416. // Pick the first unhandled StmtSequence and consider it as the
  417. // beginning
  418. // of a new CloneGroup for now.
  419. // We don't add i to Indexes because we never iterate back.
  420. StmtSequence Prototype = HashGroup[i];
  421. CloneDetector::CloneGroup PotentialGroup = {Prototype};
  422. ++Indexes[i];
  423. // Check all following StmtSequences for clones.
  424. for (unsigned j = i + 1; j < HashGroup.size(); ++j) {
  425. // Skip indexes that are already part of a CloneGroup.
  426. if (Indexes[j])
  427. continue;
  428. // If a following StmtSequence belongs to our CloneGroup, we add it.
  429. const StmtSequence &Candidate = HashGroup[j];
  430. if (!Compare(Prototype, Candidate))
  431. continue;
  432. PotentialGroup.push_back(Candidate);
  433. // Make sure we never visit this StmtSequence again.
  434. ++Indexes[j];
  435. }
  436. // Otherwise, add it to the result and continue searching for more
  437. // groups.
  438. Result.push_back(PotentialGroup);
  439. }
  440. assert(llvm::all_of(Indexes, [](char c) { return c == 1; }));
  441. }
  442. CloneGroups = Result;
  443. }
  444. void VariablePattern::addVariableOccurence(const VarDecl *VarDecl,
  445. const Stmt *Mention) {
  446. // First check if we already reference this variable
  447. for (size_t KindIndex = 0; KindIndex < Variables.size(); ++KindIndex) {
  448. if (Variables[KindIndex] == VarDecl) {
  449. // If yes, add a new occurrence that points to the existing entry in
  450. // the Variables vector.
  451. Occurences.emplace_back(KindIndex, Mention);
  452. return;
  453. }
  454. }
  455. // If this variable wasn't already referenced, add it to the list of
  456. // referenced variables and add a occurrence that points to this new entry.
  457. Occurences.emplace_back(Variables.size(), Mention);
  458. Variables.push_back(VarDecl);
  459. }
  460. void VariablePattern::addVariables(const Stmt *S) {
  461. // Sometimes we get a nullptr (such as from IfStmts which often have nullptr
  462. // children). We skip such statements as they don't reference any
  463. // variables.
  464. if (!S)
  465. return;
  466. // Check if S is a reference to a variable. If yes, add it to the pattern.
  467. if (auto D = dyn_cast<DeclRefExpr>(S)) {
  468. if (auto VD = dyn_cast<VarDecl>(D->getDecl()->getCanonicalDecl()))
  469. addVariableOccurence(VD, D);
  470. }
  471. // Recursively check all children of the given statement.
  472. for (const Stmt *Child : S->children()) {
  473. addVariables(Child);
  474. }
  475. }
  476. unsigned VariablePattern::countPatternDifferences(
  477. const VariablePattern &Other,
  478. VariablePattern::SuspiciousClonePair *FirstMismatch) {
  479. unsigned NumberOfDifferences = 0;
  480. assert(Other.Occurences.size() == Occurences.size());
  481. for (unsigned i = 0; i < Occurences.size(); ++i) {
  482. auto ThisOccurence = Occurences[i];
  483. auto OtherOccurence = Other.Occurences[i];
  484. if (ThisOccurence.KindID == OtherOccurence.KindID)
  485. continue;
  486. ++NumberOfDifferences;
  487. // If FirstMismatch is not a nullptr, we need to store information about
  488. // the first difference between the two patterns.
  489. if (FirstMismatch == nullptr)
  490. continue;
  491. // Only proceed if we just found the first difference as we only store
  492. // information about the first difference.
  493. if (NumberOfDifferences != 1)
  494. continue;
  495. const VarDecl *FirstSuggestion = nullptr;
  496. // If there is a variable available in the list of referenced variables
  497. // which wouldn't break the pattern if it is used in place of the
  498. // current variable, we provide this variable as the suggested fix.
  499. if (OtherOccurence.KindID < Variables.size())
  500. FirstSuggestion = Variables[OtherOccurence.KindID];
  501. // Store information about the first clone.
  502. FirstMismatch->FirstCloneInfo =
  503. VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
  504. Variables[ThisOccurence.KindID], ThisOccurence.Mention,
  505. FirstSuggestion);
  506. // Same as above but with the other clone. We do this for both clones as
  507. // we don't know which clone is the one containing the unintended
  508. // pattern error.
  509. const VarDecl *SecondSuggestion = nullptr;
  510. if (ThisOccurence.KindID < Other.Variables.size())
  511. SecondSuggestion = Other.Variables[ThisOccurence.KindID];
  512. // Store information about the second clone.
  513. FirstMismatch->SecondCloneInfo =
  514. VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
  515. Other.Variables[OtherOccurence.KindID], OtherOccurence.Mention,
  516. SecondSuggestion);
  517. // SuspiciousClonePair guarantees that the first clone always has a
  518. // suggested variable associated with it. As we know that one of the two
  519. // clones in the pair always has suggestion, we swap the two clones
  520. // in case the first clone has no suggested variable which means that
  521. // the second clone has a suggested variable and should be first.
  522. if (!FirstMismatch->FirstCloneInfo.Suggestion)
  523. std::swap(FirstMismatch->FirstCloneInfo, FirstMismatch->SecondCloneInfo);
  524. // This ensures that we always have at least one suggestion in a pair.
  525. assert(FirstMismatch->FirstCloneInfo.Suggestion);
  526. }
  527. return NumberOfDifferences;
  528. }