xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp (revision ba816326f336beddd19e59067577d4bf0e592efa)
1 //===--- CloneChecker.cpp - Clone detection checker -------------*- C++ -*-===//
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 /// \file
11 /// CloneChecker is a checker that reports clones in the current translation
12 /// unit.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "ClangSACheckers.h"
17 #include "clang/Analysis/CloneDetection.h"
18 #include "clang/Basic/Diagnostic.h"
19 #include "clang/StaticAnalyzer/Core/Checker.h"
20 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class CloneChecker
28     : public Checker<check::ASTCodeBody, check::EndOfTranslationUnit> {
29   mutable CloneDetector CloneDetector;
30 
31 public:
32   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
33                         BugReporter &BR) const;
34 
35   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
36                                  AnalysisManager &Mgr, BugReporter &BR) const;
37 };
38 } // end anonymous namespace
39 
40 void CloneChecker::checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
41                                     BugReporter &BR) const {
42   // Every statement that should be included in the search for clones needs to
43   // be passed to the CloneDetector.
44   CloneDetector.analyzeCodeBody(D);
45 }
46 
47 void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
48                                              AnalysisManager &Mgr,
49                                              BugReporter &BR) const {
50   // At this point, every statement in the translation unit has been analyzed by
51   // the CloneDetector. The only thing left to do is to report the found clones.
52 
53   int MinComplexity = Mgr.getAnalyzerOptions().getOptionAsInteger(
54       "MinimumCloneComplexity", 10, this);
55 
56   assert(MinComplexity >= 0);
57 
58   SourceManager &SM = BR.getSourceManager();
59 
60   std::vector<CloneDetector::CloneGroup> CloneGroups;
61   CloneDetector.findClones(CloneGroups, MinComplexity);
62 
63   DiagnosticsEngine &DiagEngine = Mgr.getDiagnostic();
64 
65   unsigned WarnID = DiagEngine.getCustomDiagID(DiagnosticsEngine::Warning,
66                                                "Detected code clone.");
67 
68   unsigned NoteID = DiagEngine.getCustomDiagID(DiagnosticsEngine::Note,
69                                                "Related code clone is here.");
70 
71   for (CloneDetector::CloneGroup &Group : CloneGroups) {
72     // For readability reasons we sort the clones by line numbers.
73     std::sort(Group.Sequences.begin(), Group.Sequences.end(),
74               [&SM](const StmtSequence &LHS, const StmtSequence &RHS) {
75                 return SM.isBeforeInTranslationUnit(LHS.getStartLoc(),
76                                                     RHS.getStartLoc()) &&
77                        SM.isBeforeInTranslationUnit(LHS.getEndLoc(),
78                                                     RHS.getEndLoc());
79               });
80 
81     // We group the clones by printing the first as a warning and all others
82     // as a note.
83     DiagEngine.Report(Group.Sequences.front().getStartLoc(), WarnID);
84     for (unsigned i = 1; i < Group.Sequences.size(); ++i) {
85       DiagEngine.Report(Group.Sequences[i].getStartLoc(), NoteID);
86     }
87   }
88 }
89 
90 //===----------------------------------------------------------------------===//
91 // Register CloneChecker
92 //===----------------------------------------------------------------------===//
93 
94 void ento::registerCloneChecker(CheckerManager &Mgr) {
95   Mgr.registerChecker<CloneChecker>();
96 }
97