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
19namespace clang {
20namespace ento {
21namespace {
22
23class TestReturnValueUnderConstructionChecker
24 : public Checker<check::PostCall> {
25public:
26 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>(Val: RetVal->getAsRegion());
41 const Expr *OrigExpr = Call.getOriginExpr();
42 ASSERT_EQ(OrigExpr->getType()->getCanonicalTypeInternal(),
43 RetReg->getValueType()->getCanonicalTypeInternal());
44 }
45};
46
47void addTestReturnValueUnderConstructionChecker(
48 AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
49 AnOpts.CheckersAndPackages =
50 {{"test.TestReturnValueUnderConstruction", true}};
51 AnalysisConsumer.AddCheckerRegistrationFn(Fn: [](CheckerRegistry &Registry) {
52 Registry.addChecker<TestReturnValueUnderConstructionChecker>(
53 FullName: "test.TestReturnValueUnderConstruction", Desc: "", DocsUri: "");
54 });
55}
56
57TEST(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

source code of clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp