| // 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 <cassert> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "absl/strings/str_format.h" | 
 | #include "absl/strings/str_join.h" | 
 | #include "lifetime_analysis/object.h" | 
 | #include "lifetime_analysis/object_set.h" | 
 | #include "lifetime_annotations/lifetime.h" | 
 | #include "clang/AST/Expr.h" | 
 | #include "clang/Basic/LLVM.h" | 
 | #include "llvm/Support/ErrorHandling.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 |  | 
 | namespace clang { | 
 | namespace tidy { | 
 | namespace lifetimes { | 
 |  | 
 | bool PointsToMap::operator==(const PointsToMap& other) const { | 
 |   return pointer_points_tos_ == other.pointer_points_tos_ && | 
 |          expr_objects_ == other.expr_objects_; | 
 | } | 
 |  | 
 | std::string PointsToMap::DebugString() const { | 
 |   std::vector<std::string> parts; | 
 |   for (const auto& [pointer, points_to] : pointer_points_tos_) { | 
 |     parts.push_back(absl::StrFormat("%s -> %s", pointer->DebugString(), | 
 |                                     points_to.DebugString())); | 
 |   } | 
 |   for (const auto& [expr, objects] : expr_objects_) { | 
 |     parts.push_back(absl::StrFormat("%s (%p) -> %s", expr->getStmtClassName(), | 
 |                                     expr, objects.DebugString())); | 
 |   } | 
 |   return absl::StrJoin(parts, "\n"); | 
 | } | 
 |  | 
 | PointsToMap PointsToMap::Union(const PointsToMap& other) const { | 
 |   PointsToMap result; | 
 |  | 
 |   result.pointer_points_tos_ = pointer_points_tos_; | 
 |   for (const auto& [pointer, points_to] : other.pointer_points_tos_) { | 
 |     result.pointer_points_tos_[pointer].Add(points_to); | 
 |   } | 
 |   // TODO(mboehme): Do we even need to perform a union on expression object | 
 |   // sets? | 
 |   result.expr_objects_ = expr_objects_; | 
 |   for (const auto& [expr, objects] : other.expr_objects_) { | 
 |     result.expr_objects_[expr].Add(objects); | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | ObjectSet PointsToMap::GetPointerPointsToSet(const Object* pointer) const { | 
 |   auto iter = pointer_points_tos_.find(pointer); | 
 |   if (iter == pointer_points_tos_.end()) { | 
 |     return ObjectSet(); | 
 |   } | 
 |   return iter->second; | 
 | } | 
 |  | 
 | void PointsToMap::SetPointerPointsToSet(const Object* pointer, | 
 |                                         ObjectSet points_to) { | 
 |   pointer_points_tos_[pointer] = std::move(points_to); | 
 | } | 
 |  | 
 | void PointsToMap::SetPointerPointsToSet(const ObjectSet& pointers, | 
 |                                         const ObjectSet& points_to) { | 
 |   for (const Object* pointer : pointers) { | 
 |     SetPointerPointsToSet(pointer, points_to); | 
 |   } | 
 | } | 
 |  | 
 | void PointsToMap::ExtendPointerPointsToSet(const Object* pointer, | 
 |                                            const ObjectSet& points_to) { | 
 |   ObjectSet& set = pointer_points_tos_[pointer]; | 
 |   set.Add(points_to); | 
 | } | 
 |  | 
 | ObjectSet PointsToMap::GetPointerPointsToSet(const ObjectSet& pointers) const { | 
 |   ObjectSet result; | 
 |   for (const Object* pointer : pointers) { | 
 |     auto iter = pointer_points_tos_.find(pointer); | 
 |     if (iter != pointer_points_tos_.end()) { | 
 |       result.Add(iter->second); | 
 |     } | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | ObjectSet PointsToMap::GetExprObjectSet(const clang::Expr* expr) const { | 
 |   // We can't handle `ParenExpr`s like other `Expr`s because the CFG doesn't | 
 |   // contain `CFGStmt`s for them. Instead, if we encounter a `ParenExpr` here, | 
 |   // we simply return the object set for its subexpression. | 
 |   if (auto paren = clang::dyn_cast<clang::ParenExpr>(expr)) { | 
 |     expr = paren->getSubExpr(); | 
 |   } | 
 |  | 
 |   assert(expr->isGLValue() || expr->getType()->isPointerType() || | 
 |          expr->getType()->isArrayType() || expr->getType()->isFunctionType() || | 
 |          expr->getType()->isBuiltinType()); | 
 |  | 
 |   auto iter = expr_objects_.find(expr); | 
 |   if (iter == expr_objects_.end()) { | 
 |     llvm::errs() << "Didn't find object set for expression:\n"; | 
 |     expr->dump(); | 
 |     llvm::report_fatal_error("Didn't find object set for expression"); | 
 |   } | 
 |   return iter->second; | 
 | } | 
 |  | 
 | bool PointsToMap::ExprHasObjectSet(const clang::Expr* expr) const { | 
 |   auto iter = expr_objects_.find(expr->IgnoreParens()); | 
 |   return (iter != expr_objects_.end()); | 
 | } | 
 |  | 
 | void PointsToMap::SetExprObjectSet(const clang::Expr* expr, ObjectSet objects) { | 
 |   assert(expr->isGLValue() || expr->getType()->isPointerType() || | 
 |          expr->getType()->isArrayType() || expr->getType()->isBuiltinType()); | 
 |   expr_objects_[expr] = std::move(objects); | 
 | } | 
 |  | 
 | std::vector<const Object*> PointsToMap::GetAllPointersWithLifetime( | 
 |     Lifetime lifetime) const { | 
 |   std::vector<const Object*> result; | 
 |   for (const auto& [pointer, _] : pointer_points_tos_) { | 
 |     if (pointer->GetLifetime() == lifetime) { | 
 |       result.push_back(pointer); | 
 |     } | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | }  // namespace lifetimes | 
 | }  // namespace tidy | 
 | }  // namespace clang |