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:
25   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
26     // Only calls with origin expression are checked. These are `returnC()`
27     // and C::C().
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 };
40 
41 void addTestReturnValueUnderConstructionChecker(
42     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
43   AnOpts.CheckersAndPackages =
44     {{"test.TestReturnValueUnderConstruction", true}};
45   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
46       Registry.addChecker<TestReturnValueUnderConstructionChecker>(
47           "test.TestReturnValueUnderConstruction", "", "");
48     });
49 }
50 
51 TEST(TestReturnValueUnderConstructionChecker,
52      ReturnValueUnderConstructionChecker) {
53   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
54                   R"(class C {
55                      public:
56                        C(int nn): n(nn) {}
57                        virtual ~C() {}
58                      private:
59                        int n;
60                      };
61 
62                      C returnC(int m) {
63                        C c(m);
64                        return c;
65                      }
66 
67                      void foo() {
68                        C c = returnC(1);
69                      })"));
70 }
71 
72 } // namespace
73 } // namespace ento
74 } // namespace clang
75