]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
Import zstandard 1.1.4 in base
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / CloneChecker.cpp
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/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24
25 using namespace clang;
26 using namespace ento;
27
28 namespace {
29 class CloneChecker
30     : public Checker<check::ASTCodeBody, check::EndOfTranslationUnit> {
31   mutable CloneDetector Detector;
32   mutable std::unique_ptr<BugType> BT_Exact, BT_Suspicious;
33
34 public:
35   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
36                         BugReporter &BR) const;
37
38   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
39                                  AnalysisManager &Mgr, BugReporter &BR) const;
40
41   /// \brief Reports all clones to the user.
42   void reportClones(BugReporter &BR, AnalysisManager &Mgr,
43                     int MinComplexity) const;
44
45   /// \brief Reports only suspicious clones to the user along with informaton
46   ///        that explain why they are suspicious.
47   void reportSuspiciousClones(BugReporter &BR, AnalysisManager &Mgr,
48                               int MinComplexity) const;
49 };
50 } // end anonymous namespace
51
52 void CloneChecker::checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
53                                     BugReporter &BR) const {
54   // Every statement that should be included in the search for clones needs to
55   // be passed to the CloneDetector.
56   Detector.analyzeCodeBody(D);
57 }
58
59 void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
60                                              AnalysisManager &Mgr,
61                                              BugReporter &BR) const {
62   // At this point, every statement in the translation unit has been analyzed by
63   // the CloneDetector. The only thing left to do is to report the found clones.
64
65   int MinComplexity = Mgr.getAnalyzerOptions().getOptionAsInteger(
66       "MinimumCloneComplexity", 10, this);
67   assert(MinComplexity >= 0);
68
69   bool ReportSuspiciousClones = Mgr.getAnalyzerOptions().getBooleanOption(
70       "ReportSuspiciousClones", true, this);
71
72   bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
73       "ReportNormalClones", true, this);
74
75   if (ReportSuspiciousClones)
76     reportSuspiciousClones(BR, Mgr, MinComplexity);
77
78   if (ReportNormalClones)
79     reportClones(BR, Mgr, MinComplexity);
80 }
81
82 static PathDiagnosticLocation makeLocation(const StmtSequence &S,
83                                            AnalysisManager &Mgr) {
84   ASTContext &ACtx = Mgr.getASTContext();
85   return PathDiagnosticLocation::createBegin(
86       S.front(), ACtx.getSourceManager(),
87       Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl()));
88 }
89
90 void CloneChecker::reportClones(BugReporter &BR, AnalysisManager &Mgr,
91                                 int MinComplexity) const {
92
93   std::vector<CloneDetector::CloneGroup> CloneGroups;
94   Detector.findClones(CloneGroups, MinComplexity);
95
96   if (!BT_Exact)
97     BT_Exact.reset(new BugType(this, "Exact code clone", "Code clone"));
98
99   for (CloneDetector::CloneGroup &Group : CloneGroups) {
100     // We group the clones by printing the first as a warning and all others
101     // as a note.
102     auto R = llvm::make_unique<BugReport>(
103         *BT_Exact, "Duplicate code detected",
104         makeLocation(Group.Sequences.front(), Mgr));
105     R->addRange(Group.Sequences.front().getSourceRange());
106
107     for (unsigned i = 1; i < Group.Sequences.size(); ++i)
108       R->addNote("Similar code here",
109                       makeLocation(Group.Sequences[i], Mgr),
110                       Group.Sequences[i].getSourceRange());
111     BR.emitReport(std::move(R));
112   }
113 }
114
115 void CloneChecker::reportSuspiciousClones(BugReporter &BR,
116                                           AnalysisManager &Mgr,
117                                           int MinComplexity) const {
118
119   std::vector<CloneDetector::SuspiciousClonePair> Clones;
120   Detector.findSuspiciousClones(Clones, MinComplexity);
121
122   if (!BT_Suspicious)
123     BT_Suspicious.reset(
124         new BugType(this, "Suspicious code clone", "Code clone"));
125
126   ASTContext &ACtx = BR.getContext();
127   SourceManager &SM = ACtx.getSourceManager();
128   AnalysisDeclContext *ADC =
129       Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl());
130
131   for (CloneDetector::SuspiciousClonePair &Pair : Clones) {
132     // FIXME: We are ignoring the suggestions currently, because they are
133     // only 50% accurate (even if the second suggestion is unavailable),
134     // which may confuse the user.
135     // Think how to perform more accurate suggestions?
136
137     auto R = llvm::make_unique<BugReport>(
138         *BT_Suspicious,
139         "Potential copy-paste error; did you really mean to use '" +
140             Pair.FirstCloneInfo.Variable->getNameAsString() + "' here?",
141         PathDiagnosticLocation::createBegin(Pair.FirstCloneInfo.Mention, SM,
142                                             ADC));
143     R->addRange(Pair.FirstCloneInfo.Mention->getSourceRange());
144
145     R->addNote("Similar code using '" +
146                    Pair.SecondCloneInfo.Variable->getNameAsString() + "' here",
147                PathDiagnosticLocation::createBegin(Pair.SecondCloneInfo.Mention,
148                                                    SM, ADC),
149                Pair.SecondCloneInfo.Mention->getSourceRange());
150
151     BR.emitReport(std::move(R));
152   }
153 }
154
155 //===----------------------------------------------------------------------===//
156 // Register CloneChecker
157 //===----------------------------------------------------------------------===//
158
159 void ento::registerCloneChecker(CheckerManager &Mgr) {
160   Mgr.registerChecker<CloneChecker>();
161 }