xref: /llvm-project/clang/unittests/StaticAnalyzer/CallEventTest.cpp (revision 45b360d4a2c751dd5afa0c676e2badf46cd29f01)
19d69072fSKirstóf Umann //===----------------------------------------------------------------------===//
29d69072fSKirstóf Umann //
39d69072fSKirstóf Umann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49d69072fSKirstóf Umann // See https://llvm.org/LICENSE.txt for license information.
59d69072fSKirstóf Umann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69d69072fSKirstóf Umann //
79d69072fSKirstóf Umann //===----------------------------------------------------------------------===//
89d69072fSKirstóf Umann 
99d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
109d69072fSKirstóf Umann #include "CheckerRegistration.h"
119d69072fSKirstóf Umann #include "clang/Basic/LLVM.h"
129d69072fSKirstóf Umann #include "clang/Frontend/CompilerInstance.h"
139d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
149d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
159d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
169d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/Checker.h"
179d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
189d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
199d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
209d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
219d69072fSKirstóf Umann #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
229d69072fSKirstóf Umann #include "clang/Tooling/Tooling.h"
239d69072fSKirstóf Umann #include "gtest/gtest.h"
249d69072fSKirstóf Umann 
259d69072fSKirstóf Umann namespace clang {
269d69072fSKirstóf Umann namespace ento {
279d69072fSKirstóf Umann namespace {
289d69072fSKirstóf Umann 
reportBug(const CheckerBase * Checker,const CallEvent & Call,CheckerContext & C,StringRef WarningMsg)299d69072fSKirstóf Umann void reportBug(const CheckerBase *Checker, const CallEvent &Call,
309d69072fSKirstóf Umann                CheckerContext &C, StringRef WarningMsg) {
319d69072fSKirstóf Umann   C.getBugReporter().EmitBasicReport(
329d69072fSKirstóf Umann       nullptr, Checker, "", categories::LogicError, WarningMsg,
339d69072fSKirstóf Umann       PathDiagnosticLocation(Call.getOriginExpr(), C.getSourceManager(),
349d69072fSKirstóf Umann                              C.getLocationContext()),
359d69072fSKirstóf Umann       {});
369d69072fSKirstóf Umann }
379d69072fSKirstóf Umann 
389d69072fSKirstóf Umann class CXXDeallocatorChecker : public Checker<check::PreCall> {
399d69072fSKirstóf Umann public:
checkPreCall(const CallEvent & Call,CheckerContext & C) const409d69072fSKirstóf Umann   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
419d69072fSKirstóf Umann     const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call);
429d69072fSKirstóf Umann     if (!DC) {
439d69072fSKirstóf Umann       return;
449d69072fSKirstóf Umann     }
459d69072fSKirstóf Umann 
469d69072fSKirstóf Umann     SmallString<100> WarningBuf;
479d69072fSKirstóf Umann     llvm::raw_svector_ostream WarningOS(WarningBuf);
489d69072fSKirstóf Umann     WarningOS << "NumArgs: " << DC->getNumArgs();
499d69072fSKirstóf Umann 
509d69072fSKirstóf Umann     reportBug(this, *DC, C, WarningBuf);
519d69072fSKirstóf Umann   }
529d69072fSKirstóf Umann };
539d69072fSKirstóf Umann 
addCXXDeallocatorChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)549d69072fSKirstóf Umann void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,
559d69072fSKirstóf Umann                               AnalyzerOptions &AnOpts) {
569d69072fSKirstóf Umann   AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};
579d69072fSKirstóf Umann   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
589d69072fSKirstóf Umann     Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",
599d69072fSKirstóf Umann                                                "Description", "");
609d69072fSKirstóf Umann   });
619d69072fSKirstóf Umann }
629d69072fSKirstóf Umann 
639d69072fSKirstóf Umann // TODO: What we should really be testing here is all the different varieties
649d69072fSKirstóf Umann // of delete operators, and wether the retrieval of their arguments works as
659d69072fSKirstóf Umann // intended. At the time of writing this file, CXXDeallocatorCall doesn't pick
669d69072fSKirstóf Umann // up on much of those due to the AST not containing CXXDeleteExpr for most of
679d69072fSKirstóf Umann // the standard/custom deletes.
TEST(CXXDeallocatorCall,SimpleDestructor)689d69072fSKirstóf Umann TEST(CXXDeallocatorCall, SimpleDestructor) {
699d69072fSKirstóf Umann   std::string Diags;
709d69072fSKirstóf Umann   EXPECT_TRUE(runCheckerOnCode<addCXXDeallocatorChecker>(R"(
719d69072fSKirstóf Umann     struct A {};
729d69072fSKirstóf Umann 
739d69072fSKirstóf Umann     void f() {
749d69072fSKirstóf Umann       A *a = new A;
759d69072fSKirstóf Umann       delete a;
769d69072fSKirstóf Umann     }
779d69072fSKirstóf Umann   )",
789d69072fSKirstóf Umann                                                          Diags));
79*45b360d4SMartin Storsjö #if defined(_AIX) || defined(__MVS__) || defined(__MINGW32__)
80*45b360d4SMartin Storsjö   // AIX, ZOS and MinGW default to -fno-sized-deallocation.
81668ee3f5SXing Xue   EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 1\n");
82668ee3f5SXing Xue #else
83130e93ccSPengcheng Wang   EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 2\n");
84668ee3f5SXing Xue #endif
859d69072fSKirstóf Umann }
869d69072fSKirstóf Umann 
879d69072fSKirstóf Umann } // namespace
889d69072fSKirstóf Umann } // namespace ento
899d69072fSKirstóf Umann } // namespace clang
90