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