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