Open-source lifetime inference/verification code.

PiperOrigin-RevId: 450954978
diff --git a/lifetime_analysis/test/function_templates.cc b/lifetime_analysis/test/function_templates.cc
new file mode 100644
index 0000000..dd90beb
--- /dev/null
+++ b/lifetime_analysis/test/function_templates.cc
@@ -0,0 +1,154 @@
+// 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 involving function templates.
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "lifetime_analysis/test/lifetime_analysis_test.h"
+
+namespace clang {
+namespace tidy {
+namespace lifetimes {
+namespace {
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplatePtr) {
+  EXPECT_THAT(GetLifetimesWithPlaceholder(R"(
+    template <typename T>
+    T* target(T* t) {
+      return t;
+    }
+  )"),
+              LifetimesAre({{"target", "a -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplatePtrWithTwoArgs) {
+  EXPECT_THAT(GetLifetimesWithPlaceholder(R"(
+    template <typename T, typename U>
+    T* target(T* t, U* u1, U& u2) {
+      u1 = &u2;
+      return t;
+    }
+  )"),
+              LifetimesAre({{"target", "a, b, c -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplatePtrWithTemplatedStruct) {
+  EXPECT_THAT(GetLifetimesWithPlaceholder(R"(
+    template <typename T>
+    struct S {
+      T t;
+    };
+
+    template <typename T>
+    T* target(S<T*>* s) {
+      return s->t;
+    }
+  )"),
+              LifetimesAre({{"target", "(a, b) -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplatePtrWithMultipleFunctions) {
+  // The code has both template and non-template functions/code.
+  EXPECT_THAT(GetLifetimesWithPlaceholder(R"(
+    static int x = 3;
+    template <typename T>
+    struct A {
+      T x;
+      T y;
+    };
+    template <typename T>
+    T* target(T* t) {
+      return t;
+    }
+    template <typename U>
+    U* target2(U* u) {
+      return u;
+    }
+    int foo(A<int>* a) {
+      return a->x + a->y + x;
+    }
+  )"),
+              LifetimesAre(
+                  {{"target", "a -> a"}, {"target2", "a -> a"}, {"foo", "a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplateCall) {
+  EXPECT_THAT(GetLifetimes(R"(
+    template <typename T>
+    T* t(T* a, T* b) {
+      if (*a > *b) {
+        return a;
+      }
+      return b;
+    }
+    int* target(int* a, int* b) {
+      return t(a, b);
+    }
+  )"),
+              LifetimesContain({{"target", "a, a -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplateCallIgnoreArg) {
+  EXPECT_THAT(GetLifetimes(R"(
+    template <typename T>
+    T* t(T* a, T* b) {
+      return a;
+    }
+    int* target(int* a, int* b) {
+      return t(a, b);
+    }
+  )"),
+              LifetimesContain({{"target", "a, b -> a"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplateCallPtrInstantiation) {
+  EXPECT_THAT(GetLifetimes(R"(
+    template <typename T>
+    T* t(T* a, T* b) {
+      if (*a > *b) {
+        return a;
+      }
+      return b;
+    }
+    int** target(int** a, int** b) {
+      return t(a, b);
+    }
+  )"),
+              LifetimesContain({{"target", "(a, b), (a, b) -> (a, b)"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplateCallIgnoreArgPtrInstantiation) {
+  EXPECT_THAT(GetLifetimes(R"(
+    template <typename T>
+    T* t(T* a, T* b) {
+      return a;
+    }
+    int** target(int** a, int** b) {
+      return t(a, b);
+    }
+  )"),
+              LifetimesContain({{"target", "(a, b), (c, d) -> (a, b)"}}));
+}
+
+TEST_F(LifetimeAnalysisTest, FunctionTemplateInsideClassTemplate) {
+  EXPECT_THAT(GetLifetimes(R"(
+    template <typename T>
+    struct S {
+      template <typename U>
+      U f(T t, U u) {
+        return u;
+      }
+    };
+    int* target(S<int *>& s, int* p1, int* p2) {
+      return s.f(p1, p2);
+    }
+  )"),
+              LifetimesContain({{"target", "(a, b), c, d -> d"}}));
+}
+
+}  // namespace
+}  // namespace lifetimes
+}  // namespace tidy
+}  // namespace clang