blob: c6f648b9039270621c4bc5c1375d8f6ac7f1ea79 [file] [log] [blame]
// 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