xref: /llvm-project/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp (revision 6ad0788c332bb2043142954d300c49ac3e537f34)
1813734daSAdam Balogh //===- unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp ------===//
2813734daSAdam Balogh //
3813734daSAdam Balogh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4813734daSAdam Balogh // See https://llvm.org/LICENSE.txt for license information.
5813734daSAdam Balogh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6813734daSAdam Balogh //
7813734daSAdam Balogh //===----------------------------------------------------------------------===//
8813734daSAdam Balogh 
9813734daSAdam Balogh #include "CheckerRegistration.h"
10813734daSAdam Balogh #include "clang/StaticAnalyzer/Core/Checker.h"
11813734daSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
12813734daSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
13813734daSAdam Balogh #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
14813734daSAdam Balogh #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
15813734daSAdam Balogh #include "clang/Tooling/Tooling.h"
16813734daSAdam Balogh #include "gtest/gtest.h"
17a1580d7bSKazu Hirata #include <optional>
18813734daSAdam Balogh 
19813734daSAdam Balogh namespace clang {
20813734daSAdam Balogh namespace ento {
21813734daSAdam Balogh namespace {
22813734daSAdam Balogh 
23813734daSAdam Balogh class TestReturnValueUnderConstructionChecker
24813734daSAdam Balogh   : public Checker<check::PostCall> {
25813734daSAdam Balogh public:
checkPostCall(const CallEvent & Call,CheckerContext & C) const26813734daSAdam Balogh   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
27facad21bSAdam Balogh     // Only calls with origin expression are checked. These are `returnC()`,
28facad21bSAdam Balogh     // `returnD()`, C::C() and D::D().
29e22ace8bSAdam Balogh     if (!Call.getOriginExpr())
30813734daSAdam Balogh       return;
31813734daSAdam Balogh 
32813734daSAdam Balogh     // Since `returnC` returns an object by value, the invocation results
33813734daSAdam Balogh     // in an object of type `C` constructed into variable `c`. Thus the
34813734daSAdam Balogh     // return value of `CallEvent::getReturnValueUnderConstruction()` must
35813734daSAdam Balogh     // be non-empty and has to be a `MemRegion`.
36*6ad0788cSKazu Hirata     std::optional<SVal> RetVal = Call.getReturnValueUnderConstruction();
37813734daSAdam Balogh     ASSERT_TRUE(RetVal);
38813734daSAdam Balogh     ASSERT_TRUE(RetVal->getAsRegion());
39facad21bSAdam Balogh 
40facad21bSAdam Balogh     const auto *RetReg = cast<TypedValueRegion>(RetVal->getAsRegion());
41facad21bSAdam Balogh     const Expr *OrigExpr = Call.getOriginExpr();
4215f3cd6bSMatheus Izvekov     ASSERT_EQ(OrigExpr->getType()->getCanonicalTypeInternal(),
4315f3cd6bSMatheus Izvekov               RetReg->getValueType()->getCanonicalTypeInternal());
44813734daSAdam Balogh   }
45813734daSAdam Balogh };
46813734daSAdam Balogh 
addTestReturnValueUnderConstructionChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)47813734daSAdam Balogh void addTestReturnValueUnderConstructionChecker(
48813734daSAdam Balogh     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
49813734daSAdam Balogh   AnOpts.CheckersAndPackages =
50813734daSAdam Balogh     {{"test.TestReturnValueUnderConstruction", true}};
51813734daSAdam Balogh   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
52813734daSAdam Balogh       Registry.addChecker<TestReturnValueUnderConstructionChecker>(
53813734daSAdam Balogh           "test.TestReturnValueUnderConstruction", "", "");
54813734daSAdam Balogh     });
55813734daSAdam Balogh }
56813734daSAdam Balogh 
TEST(TestReturnValueUnderConstructionChecker,ReturnValueUnderConstructionChecker)57813734daSAdam Balogh TEST(TestReturnValueUnderConstructionChecker,
58813734daSAdam Balogh      ReturnValueUnderConstructionChecker) {
59813734daSAdam Balogh   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
60813734daSAdam Balogh       R"(class C {
61813734daSAdam Balogh          public:
62813734daSAdam Balogh            C(int nn): n(nn) {}
63813734daSAdam Balogh            virtual ~C() {}
64813734daSAdam Balogh          private:
65813734daSAdam Balogh            int n;
66813734daSAdam Balogh          };
67813734daSAdam Balogh 
68813734daSAdam Balogh          C returnC(int m) {
69813734daSAdam Balogh            C c(m);
70813734daSAdam Balogh            return c;
71813734daSAdam Balogh          }
72813734daSAdam Balogh 
73813734daSAdam Balogh          void foo() {
74813734daSAdam Balogh            C c = returnC(1);
75813734daSAdam Balogh          })"));
76facad21bSAdam Balogh 
77facad21bSAdam Balogh   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
78facad21bSAdam Balogh       R"(class C {
79facad21bSAdam Balogh          public:
80facad21bSAdam Balogh            C(int nn): n(nn) {}
81facad21bSAdam Balogh            explicit C(): C(0) {}
82facad21bSAdam Balogh            virtual ~C() {}
83facad21bSAdam Balogh          private:
84facad21bSAdam Balogh            int n;
85facad21bSAdam Balogh          };
86facad21bSAdam Balogh 
87facad21bSAdam Balogh          C returnC() {
88facad21bSAdam Balogh            C c;
89facad21bSAdam Balogh            return c;
90facad21bSAdam Balogh          }
91facad21bSAdam Balogh 
92facad21bSAdam Balogh          void foo() {
93facad21bSAdam Balogh            C c = returnC();
94facad21bSAdam Balogh          })"));
95facad21bSAdam Balogh 
96facad21bSAdam Balogh   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
97facad21bSAdam Balogh       R"(class C {
98facad21bSAdam Balogh          public:
99facad21bSAdam Balogh            C(int nn): n(nn) {}
100facad21bSAdam Balogh            virtual ~C() {}
101facad21bSAdam Balogh          private:
102facad21bSAdam Balogh            int n;
103facad21bSAdam Balogh          };
104facad21bSAdam Balogh 
105facad21bSAdam Balogh          class D: public C {
106facad21bSAdam Balogh          public:
107facad21bSAdam Balogh            D(int nn): C(nn) {}
108facad21bSAdam Balogh            virtual ~D() {}
109facad21bSAdam Balogh          };
110facad21bSAdam Balogh 
111facad21bSAdam Balogh          D returnD(int m) {
112facad21bSAdam Balogh            D d(m);
113facad21bSAdam Balogh            return d;
114facad21bSAdam Balogh          }
115facad21bSAdam Balogh 
116facad21bSAdam Balogh          void foo() {
117facad21bSAdam Balogh            D d = returnD(1);
118facad21bSAdam Balogh          })"));
119813734daSAdam Balogh }
120813734daSAdam Balogh 
121813734daSAdam Balogh } // namespace
122813734daSAdam Balogh } // namespace ento
123813734daSAdam Balogh } // namespace clang
124