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