blob: 87c813df5286155437abdfd2fb01d825ba58effb [file] [log] [blame]
Artem Dergachevba816322016-07-26 18:13:12 +00001//===--- 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
23using namespace clang;
24using namespace ento;
25
26namespace {
27class CloneChecker
28 : public Checker<check::ASTCodeBody, check::EndOfTranslationUnit> {
Artem Dergachev96034ca2016-07-26 19:05:22 +000029 mutable CloneDetector Detector;
Artem Dergachevba816322016-07-26 18:13:12 +000030
31public:
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
40void 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.
Artem Dergachev96034ca2016-07-26 19:05:22 +000044 Detector.analyzeCodeBody(D);
Artem Dergachevba816322016-07-26 18:13:12 +000045}
46
47void 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;
Artem Dergachev96034ca2016-07-26 19:05:22 +000061 Detector.findClones(CloneGroups, MinComplexity);
Artem Dergachevba816322016-07-26 18:13:12 +000062
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
94void ento::registerCloneChecker(CheckerManager &Mgr) {
95 Mgr.registerChecker<CloneChecker>();
96}