| // 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 |