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