xref: /llvm-project/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp (revision 6ad0788c332bb2043142954d300c49ac3e537f34)
1 //===- unittests/StaticAnalyzer/TestReturnValueUnderConstruction.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/StaticAnalyzer/Core/Checker.h"
11 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
12 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
13 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
14 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gtest/gtest.h"
17 #include <optional>
18 
19 namespace clang {
20 namespace ento {
21 namespace {
22 
23 class TestReturnValueUnderConstructionChecker
24   : public Checker<check::PostCall> {
25 public:
checkPostCall(const CallEvent & Call,CheckerContext & C) const26   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
27     // Only calls with origin expression are checked. These are `returnC()`,
28     // `returnD()`, C::C() and D::D().
29     if (!Call.getOriginExpr())
30       return;
31 
32     // Since `returnC` returns an object by value, the invocation results
33     // in an object of type `C` constructed into variable `c`. Thus the
34     // return value of `CallEvent::getReturnValueUnderConstruction()` must
35     // be non-empty and has to be a `MemRegion`.
36     std::optional<SVal> RetVal = Call.getReturnValueUnderConstruction();
37     ASSERT_TRUE(RetVal);
38     ASSERT_TRUE(RetVal->getAsRegion());
39 
40     const auto *RetReg = cast<TypedValueRegion>(RetVal->getAsRegion());
41     const Expr *OrigExpr = Call.getOriginExpr();
42     ASSERT_EQ(OrigExpr->getType()->getCanonicalTypeInternal(),
43               RetReg->getValueType()->getCanonicalTypeInternal());
44   }
45 };
46 
addTestReturnValueUnderConstructionChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)47 void addTestReturnValueUnderConstructionChecker(
48     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
49   AnOpts.CheckersAndPackages =
50     {{"test.TestReturnValueUnderConstruction", true}};
51   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
52       Registry.addChecker<TestReturnValueUnderConstructionChecker>(
53           "test.TestReturnValueUnderConstruction", "", "");
54     });
55 }
56 
TEST(TestReturnValueUnderConstructionChecker,ReturnValueUnderConstructionChecker)57 TEST(TestReturnValueUnderConstructionChecker,
58      ReturnValueUnderConstructionChecker) {
59   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
60       R"(class C {
61          public:
62            C(int nn): n(nn) {}
63            virtual ~C() {}
64          private:
65            int n;
66          };
67 
68          C returnC(int m) {
69            C c(m);
70            return c;
71          }
72 
73          void foo() {
74            C c = returnC(1);
75          })"));
76 
77   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
78       R"(class C {
79          public:
80            C(int nn): n(nn) {}
81            explicit C(): C(0) {}
82            virtual ~C() {}
83          private:
84            int n;
85          };
86 
87          C returnC() {
88            C c;
89            return c;
90          }
91 
92          void foo() {
93            C c = returnC();
94          })"));
95 
96   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
97       R"(class C {
98          public:
99            C(int nn): n(nn) {}
100            virtual ~C() {}
101          private:
102            int n;
103          };
104 
105          class D: public C {
106          public:
107            D(int nn): C(nn) {}
108            virtual ~D() {}
109          };
110 
111          D returnD(int m) {
112            D d(m);
113            return d;
114          }
115 
116          void foo() {
117            D d = returnD(1);
118          })"));
119 }
120 
121 } // namespace
122 } // namespace ento
123 } // namespace clang
124