1 //===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CheckerRegistration.h"
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/Core/PathSensitive/CheckerContext.h"
16 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
17 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "gtest/gtest.h"
20 
21 namespace clang {
22 namespace ento {
23 namespace {
24 
25 //===----------------------------------------------------------------------===//
26 // Just a minimal test for how checker registration works with statically
27 // linked, non TableGen generated checkers.
28 //===----------------------------------------------------------------------===//
29 
30 class CustomChecker : public Checker<check::ASTCodeBody> {
31 public:
32   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
33                         BugReporter &BR) const {
34     BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
35                        "Custom diagnostic description",
36                        PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
37   }
38 };
39 
40 void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer,
41                       AnalyzerOptions &AnOpts) {
42   AnOpts.CheckersAndPackages = {{"custom.CustomChecker", true}};
43   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
44     Registry.addChecker<CustomChecker>("custom.CustomChecker", "Description",
45                                        "");
46   });
47 }
48 
49 TEST(RegisterCustomCheckers, RegisterChecker) {
50   std::string Diags;
51   EXPECT_TRUE(runCheckerOnCode<addCustomChecker>("void f() {;}", Diags));
52   EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description\n");
53 }
54 
55 //===----------------------------------------------------------------------===//
56 // Pretty much the same.
57 //===----------------------------------------------------------------------===//
58 
59 class LocIncDecChecker : public Checker<check::Location> {
60 public:
61   void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
62                      CheckerContext &C) const {
63     auto UnaryOp = dyn_cast<UnaryOperator>(S);
64     if (UnaryOp && !IsLoad) {
65       EXPECT_FALSE(UnaryOp->isIncrementOp());
66     }
67   }
68 };
69 
70 void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer,
71                          AnalyzerOptions &AnOpts) {
72   AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}};
73   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
74     Registry.addChecker<CustomChecker>("test.LocIncDecChecker", "Description",
75                                        "");
76   });
77 }
78 
79 TEST(RegisterCustomCheckers, CheckLocationIncDec) {
80   EXPECT_TRUE(
81       runCheckerOnCode<addLocIncDecChecker>("void f() { int *p; (*p)++; }"));
82 }
83 
84 } // namespace
85 } // namespace ento
86 } // namespace clang
87