]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
Vendor import of clang trunk r351319 (just before the release_80 branch
[FreeBSD/FreeBSD.git] / unittests / StaticAnalyzer / RegisterCustomCheckersTest.cpp
1 //===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
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 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
12 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13 #include "clang/StaticAnalyzer/Core/Checker.h"
14 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
15 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
16 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
17 #include "clang/Tooling/Tooling.h"
18 #include "gtest/gtest.h"
19
20 namespace clang {
21 namespace ento {
22 namespace {
23
24 template <typename CheckerT>
25 class TestAction : public ASTFrontendAction {
26   class DiagConsumer : public PathDiagnosticConsumer {
27     llvm::raw_ostream &Output;
28
29   public:
30     DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
31     void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
32                               FilesMade *filesMade) override {
33       for (const auto *PD : Diags)
34         Output << PD->getCheckName() << ":" << PD->getShortDescription();
35     }
36
37     StringRef getName() const override { return "Test"; }
38   };
39
40   llvm::raw_ostream &DiagsOutput;
41
42 public:
43   TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
44
45   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
46                                                  StringRef File) override {
47     std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
48         CreateAnalysisConsumer(Compiler);
49     AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
50     Compiler.getAnalyzerOpts()->CheckersControlList = {
51         {"custom.CustomChecker", true}};
52     AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
53       Registry.addChecker<CheckerT>("custom.CustomChecker", "Description", "");
54     });
55     return std::move(AnalysisConsumer);
56   }
57 };
58
59 template <typename CheckerT>
60 bool runCheckerOnCode(const std::string &Code, std::string &Diags) {
61   llvm::raw_string_ostream OS(Diags);
62   return tooling::runToolOnCode(new TestAction<CheckerT>(OS), Code);
63 }
64 template <typename CheckerT>
65 bool runCheckerOnCode(const std::string &Code) {
66   std::string Diags;
67   return runCheckerOnCode<CheckerT>(Code, Diags);
68 }
69
70
71 class CustomChecker : public Checker<check::ASTCodeBody> {
72 public:
73   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
74                         BugReporter &BR) const {
75     BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
76                        "Custom diagnostic description",
77                        PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
78   }
79 };
80
81 TEST(RegisterCustomCheckers, RegisterChecker) {
82   std::string Diags;
83   EXPECT_TRUE(runCheckerOnCode<CustomChecker>("void f() {;}", Diags));
84   EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description");
85 }
86
87 class LocIncDecChecker : public Checker<check::Location> {
88 public:
89   void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
90                      CheckerContext &C) const {
91     auto UnaryOp = dyn_cast<UnaryOperator>(S);
92     if (UnaryOp && !IsLoad)
93       EXPECT_FALSE(UnaryOp->isIncrementOp());
94   }
95 };
96
97 TEST(RegisterCustomCheckers, CheckLocationIncDec) {
98   EXPECT_TRUE(
99       runCheckerOnCode<LocIncDecChecker>("void f() { int *p; (*p)++; }"));
100 }
101
102 }
103 }
104 }