| // 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 |
| |
| #include "lifetime_analysis/points_to_map.h" |
| |
| #include <optional> |
| |
| #include "gtest/gtest.h" |
| #include "lifetime_analysis/object.h" |
| #include "lifetime_analysis/object_set.h" |
| #include "lifetime_annotations/lifetime.h" |
| #include "lifetime_annotations/lifetime_annotations.h" |
| #include "lifetime_annotations/test/run_on_code.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/ASTMatchers/ASTMatchFinder.h" |
| #include "clang/ASTMatchers/ASTMatchers.h" |
| |
| namespace clang { |
| namespace tidy { |
| namespace lifetimes { |
| namespace { |
| |
| const clang::CallExpr* getFirstCallExpr(const clang::ASTContext& ast_context) { |
| using clang::ast_matchers::callExpr; |
| using clang::ast_matchers::match; |
| using clang::ast_matchers::selectFirst; |
| |
| return selectFirst<clang::CallExpr>( |
| "call", match(callExpr().bind("call"), |
| const_cast<clang::ASTContext&>(ast_context))); |
| } |
| |
| TEST(PointsToMapTest, Equality) { |
| runOnCodeWithLifetimeHandlers( |
| "int *return_int_ptr();" |
| "int* p = return_int_ptr();", |
| [](const clang::ASTContext& ast_context, |
| const LifetimeAnnotationContext&) { |
| Object p1(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p2(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p3(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| const clang::CallExpr* expr = getFirstCallExpr(ast_context); |
| |
| { |
| PointsToMap map1, map2; |
| map1.SetPointerPointsToSet(&p1, {&p2}); |
| map2.SetPointerPointsToSet(&p1, {&p3}); |
| EXPECT_EQ(map1, PointsToMap(map1)); |
| EXPECT_NE(map1, PointsToMap()); |
| EXPECT_NE(map1, map2); |
| } |
| |
| { |
| PointsToMap map1, map2; |
| map1.SetExprObjectSet(expr, {&p1}); |
| map2.SetExprObjectSet(expr, {&p2}); |
| EXPECT_EQ(map1, PointsToMap(map1)); |
| EXPECT_NE(map1, PointsToMap()); |
| EXPECT_NE(map1, map2); |
| } |
| }, |
| {}); |
| } |
| |
| TEST(PointsToMapTest, Union) { |
| runOnCodeWithLifetimeHandlers( |
| "int *return_int_ptr();" |
| "int* p = return_int_ptr();", |
| [](const clang::ASTContext& ast_context, |
| const LifetimeAnnotationContext&) { |
| Object p1(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p2(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p3(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| const clang::CallExpr* expr = getFirstCallExpr(ast_context); |
| |
| PointsToMap map1, map2; |
| map1.SetPointerPointsToSet(&p1, {&p2}); |
| map2.SetPointerPointsToSet(&p1, {&p3}); |
| |
| map1.SetExprObjectSet(expr, {&p2}); |
| map2.SetExprObjectSet(expr, {&p3}); |
| |
| PointsToMap union_map = map1.Union(map2); |
| |
| EXPECT_EQ(union_map.GetPointerPointsToSet(&p1), ObjectSet({&p2, &p3})); |
| EXPECT_EQ(union_map.GetExprObjectSet(expr), ObjectSet({&p2, &p3})); |
| }, |
| {}); |
| } |
| |
| TEST(PointsToMapTest, GetPointerPointsToSet) { |
| runOnCodeWithLifetimeHandlers( |
| "", |
| [](const clang::ASTContext& ast_context, |
| const LifetimeAnnotationContext&) { |
| Object p1(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p2(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p3(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p4(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| |
| PointsToMap map; |
| |
| EXPECT_EQ(map.GetPointerPointsToSet(&p1), ObjectSet()); |
| |
| map.SetPointerPointsToSet(&p1, {&p3}); |
| map.SetPointerPointsToSet(&p2, {&p4}); |
| |
| EXPECT_EQ(map.GetPointerPointsToSet(&p1), ObjectSet({&p3})); |
| EXPECT_EQ(map.GetPointerPointsToSet({&p1, &p2}), ObjectSet({&p3, &p4})); |
| }, |
| {}); |
| } |
| |
| TEST(PointsToMapTest, ExtendPointerPointsToSet) { |
| runOnCodeWithLifetimeHandlers( |
| "", |
| [](const clang::ASTContext& ast_context, |
| const LifetimeAnnotationContext&) { |
| Object p1(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p2(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| Object p3(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| |
| PointsToMap map; |
| |
| EXPECT_EQ(map.GetPointerPointsToSet(&p1), ObjectSet()); |
| |
| map.ExtendPointerPointsToSet(&p1, {&p2}); |
| |
| EXPECT_EQ(map.GetPointerPointsToSet(&p1), ObjectSet({&p2})); |
| |
| map.ExtendPointerPointsToSet(&p1, {&p3}); |
| |
| EXPECT_EQ(map.GetPointerPointsToSet(&p1), ObjectSet({&p2, &p3})); |
| }, |
| {}); |
| } |
| |
| TEST(PointsToMapTest, GetExprObjectSet) { |
| runOnCodeWithLifetimeHandlers( |
| "int *return_int_ptr();" |
| "int* p = return_int_ptr();", |
| [](const clang::ASTContext& ast_context, |
| const LifetimeAnnotationContext&) { |
| Object p1(Lifetime::CreateLocal(), ast_context.IntTy, std::nullopt); |
| const clang::CallExpr* expr = getFirstCallExpr(ast_context); |
| |
| PointsToMap map; |
| |
| map.SetExprObjectSet(expr, {&p1}); |
| EXPECT_EQ(map.GetExprObjectSet(expr), ObjectSet({&p1})); |
| }, |
| {}); |
| } |
| |
| } // namespace |
| } // namespace lifetimes |
| } // namespace tidy |
| } // namespace clang |