xref: /llvm-project/clang/unittests/StaticAnalyzer/CallEventTest.cpp (revision 8a5cfdf7851dcdb4e16c510b133d7d0e79e43fc4)
1 //===----------------------------------------------------------------------===//
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 "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
10 #include "CheckerRegistration.h"
11 #include "clang/Basic/LLVM.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
14 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15 #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
20 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
21 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
22 #include "clang/Tooling/Tooling.h"
23 #include "gtest/gtest.h"
24 
25 namespace clang {
26 namespace ento {
27 namespace {
28 
29 void reportBug(const CheckerBase *Checker, const CallEvent &Call,
30                CheckerContext &C, StringRef WarningMsg) {
31   C.getBugReporter().EmitBasicReport(
32       nullptr, Checker, "", categories::LogicError, WarningMsg,
33       PathDiagnosticLocation(Call.getOriginExpr(), C.getSourceManager(),
34                              C.getLocationContext()),
35       {});
36 }
37 
38 class CXXDeallocatorChecker : public Checker<check::PreCall> {
39   std::unique_ptr<BugType> BT_uninitField;
40 
41 public:
42   CXXDeallocatorChecker()
43       : BT_uninitField(new BugType(this, "CXXDeallocator")) {}
44 
45   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
46     const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call);
47     if (!DC) {
48       return;
49     }
50 
51     SmallString<100> WarningBuf;
52     llvm::raw_svector_ostream WarningOS(WarningBuf);
53     WarningOS << "NumArgs: " << DC->getNumArgs();
54 
55     reportBug(this, *DC, C, WarningBuf);
56   }
57 };
58 
59 void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,
60                               AnalyzerOptions &AnOpts) {
61   AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};
62   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
63     Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",
64                                                "Description", "");
65   });
66 }
67 
68 // TODO: What we should really be testing here is all the different varieties
69 // of delete operators, and wether the retrieval of their arguments works as
70 // intended. At the time of writing this file, CXXDeallocatorCall doesn't pick
71 // up on much of those due to the AST not containing CXXDeleteExpr for most of
72 // the standard/custom deletes.
73 TEST(CXXDeallocatorCall, SimpleDestructor) {
74   std::string Diags;
75   EXPECT_TRUE(runCheckerOnCode<addCXXDeallocatorChecker>(R"(
76     struct A {};
77 
78     void f() {
79       A *a = new A;
80       delete a;
81     }
82   )",
83                                                          Diags));
84   EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 1\n");
85 }
86 
87 } // namespace
88 } // namespace ento
89 } // namespace clang
90