Open-source lifetime inference/verification code.
PiperOrigin-RevId: 450954978
diff --git a/lifetime_analysis/test/initialization.cc b/lifetime_analysis/test/initialization.cc
new file mode 100644
index 0000000..5998a6a
--- /dev/null
+++ b/lifetime_analysis/test/initialization.cc
@@ -0,0 +1,121 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Tests for initialization.
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "lifetime_analysis/test/lifetime_analysis_test.h"
+
+namespace clang {
+namespace tidy {
+namespace lifetimes {
+namespace {
+
+// TODO(danakj): Crashes trying to find the initializer expression under
+// MaterializeTemporaryExpr. Should be improved by cl/414032764.
+TEST_F(LifetimeAnalysisTest, DISABLED_VarDeclReferenceToRecordTemporary) {
+ EXPECT_THAT(GetLifetimes(R"(
+ template <typename T>
+ struct S {
+ T a;
+ };
+ int* target(int* a) {
+ const S<int*>& s = S<int*>{a};
+ return s.a;
+ }
+ )"),
+ LifetimesAre({{"target", "a -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, VarDeclReferenceToRecordTemplate) {
+ EXPECT_THAT(GetLifetimes(R"(
+ template <typename T>
+ struct S {
+ T a;
+ };
+ S<int*>* target(S<int*>* a) {
+ S<int*>& b = *a;
+ return &b;
+ }
+ )"),
+ LifetimesAre({{"target", "(a, b) -> (a, b)"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, VarDeclReferenceToRecordNoTemplate) {
+ EXPECT_THAT(GetLifetimes(R"(
+ struct [[clang::annotate("lifetime_params", "a")]] S {
+ [[clang::annotate("member_lifetimes", "a")]]
+ int* a;
+ };
+ S* target(S* a) {
+ S& b = *a;
+ return &b;
+ }
+ )"),
+ LifetimesAre({{"target", "(a, b) -> (a, b)"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, ConstructorInitReferenceToRecord) {
+ EXPECT_THAT(GetLifetimes(R"(
+ struct [[clang::annotate("lifetime_params", "a")]] S {
+ [[clang::annotate("member_lifetimes", "a")]]
+ int* a;
+ };
+ template <class Ref>
+ struct R {
+ R(S& s): s(s) {}
+ Ref s;
+ };
+ int* target(S* a) {
+ R<S&> r(*a);
+ return r.s.a;
+ }
+ )"),
+ LifetimesAre({{"R<S &>::R", "(a, b, c): (a, b)"},
+ {"target", "(a, b) -> a"}}));
+}
+
+// TODO(danakj): Fails because a nested TransferMemberExpr() ends up looking for
+// the field from the outer expr on the object of the inner expr.
+//
+// The code:
+// ObjectSet struct_points_to =
+// points_to_map.GetExprObjectSet(member->getBase());
+//
+// The AST:
+// MemberExpr 0x4027d3f2628 'int *':'int *' lvalue .p 0x4027d3f7338
+// `-MemberExpr 0x4027d3f25f8 'S<int *>':'struct S<int *>' lvalue .s
+// 0x4027d3f74c0
+// `-DeclRefExpr 0x4027d3f25d8 'R<int *>':'struct R<int *>' lvalue Var
+// 0x4027d3f6cd0 'r' 'R<int *>':'struct R<int *>'
+//
+// The p field is on struct S, but the code tries to find it on an object
+// of type R<int *>.
+TEST_F(LifetimeAnalysisTest, MemberInitReferenceToRecord) {
+ EXPECT_THAT(
+ GetLifetimes(R"(
+ template <typename P>
+ struct S {
+ P p;
+ };
+ template<typename P>
+ struct [[clang::annotate("lifetime_params", "a")]] R {
+ R(P p): ss{p} {}
+ S<P> ss;
+ [[clang::annotate("member_lifetimes", "a")]]
+ S<P>& s{ss};
+ };
+ int* target(int* a) {
+ R<int*> r(a);
+ return r.s.p;
+ }
+ )"),
+ LifetimesAre({{"R<int *>::R", "(<a> [b], b): a"}, {"target", "a -> a"}}));
+}
+
+} // namespace
+} // namespace lifetimes
+} // namespace tidy
+} // namespace clang