blob: 285dca47316749607ab4517a17214f68cf0cc201 [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
#ifndef DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_
#define DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_
#include <functional>
#include <optional>
#include <string>
#include <variant>
#include "lifetime_analysis/object.h"
#include "lifetime_analysis/object_set.h"
#include "lifetime_analysis/points_to_map.h"
#include "lifetime_annotations/type_lifetimes.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
namespace clang {
namespace tidy {
namespace lifetimes {
// A record-type expression has 2 modes:
// 1. If it's being assigned to a reference, then the contents of the expression
// are a glvalue. This is because references require an object to point to.
// 2. If it's being assigned to a record object, then the expression itself is
// not creating an object, but initializing it. So the expression's type is
// a pure value, and it acts _on_ the initializing object instead of
// producing an object.
inline bool IsInitExprInitializingARecordObject(const clang::Expr* expr) {
return expr->getType()->isRecordType() && expr->isPRValue();
}
// A repository for the objects used in the lifetime analysis of a single
// function.
// This class establishes a relationship between AST nodes (e.g. variable
// declarations) and the objects that represent them. It also stores additional
// information about objects that does not change during the analysis.
// The `ObjectRepository` only stores state that does not change during the
// analysis; it is therefore not part of the lattice.
class ObjectRepository {
private:
using MapType = llvm::DenseMap<const clang::ValueDecl*, const Object*>;
public:
// An `Object` might represent objects that have either a single value (such
// as plain variables) or multiple ones (such as arrays, or structs).
// Assignment behaves differently in the two cases.
enum class ObjectValueType {
kSingleValued,
kMultiValued,
};
// Tag struct for InitializedObject: the object being initialized is the
// return value of the function.
struct ReturnValue {};
// Maps a given struct-Object to the Object for each of its fields.
// TODO(veluca): this approach does not produce correct results when
// diamond-problem-style multiple inheritance happens.
using FieldObjects =
llvm::DenseMap<std::pair<Object, const clang::FieldDecl*>, const Object*>;
// Maps a given struct-Object to the Object for each of its bases.
using BaseObjects =
llvm::DenseMap<std::pair<Object, const clang::Type*>, const Object*>;
// Iterator refers to a pair consisting of a variable declaration and the
// object representing that variable.
using const_iterator = MapType::const_iterator;
using value_type = MapType::value_type;
// Initializes the map with objects for all variables that are declared or
// referenced in `func`.
explicit ObjectRepository(const clang::FunctionDecl* func);
// Move-only.
ObjectRepository(ObjectRepository&&) = default;
ObjectRepository& operator=(ObjectRepository&&) = default;
// Returns a human-readable representation of the mapping.
std::string DebugString() const;
const_iterator begin() const { return object_repository_.begin(); }
const_iterator end() const { return object_repository_.end(); }
// Creates an object with the given lifetime and type.
// The returned object will live as long as this `ObjectRepository`.
const Object* CreateObject(Lifetime lifetime, clang::QualType type);
// Creates an object representing a declared function.
// The returned object will live as long as this `ObjectRepository`.
const Object* CreateObjectFromFunctionDecl(const clang::FunctionDecl& func);
// Returns the object associated with a variable or function.
Object GetDeclObject(const clang::ValueDecl* decl) const;
// Returns the object associated with a materialize temporary expression.
Object GetTemporaryObject(const clang::MaterializeTemporaryExpr* expr) const;
// Returns the object representing the value of a function parameter at
// function entry.
// Note: This `Object` does not represent the parameter variable itself;
// use GetDeclObject() to retrieve that. We're using an `Object` here
// because we don't have a dedicated "value" class, but you should not
// use this object's identity in any way; i.e. no other `Object` in the
// points-to map should ever point to the object returned by this
// function.
Object GetOriginalParameterValue(const clang::ParmVarDecl* var_decl) const;
// Returns the object associated with an argument to a CallExpr.
Object GetCallExprArgumentObject(const clang::CallExpr* expr,
size_t arg_index) const;
// Returns the object associated with the `this` argument to a CallExpr that
// represents a method call. Note that this object represents the `this`
// pointer, not the object that the method is being called on.
Object GetCallExprThisPointer(const clang::CallExpr* expr) const;
// Returns the object associated with an argument to a CXXConstructExpr.
Object GetCXXConstructExprArgumentObject(const clang::CXXConstructExpr* expr,
size_t arg_index) const;
// Returns the object associated with the `this` argument to a
// CXXConstructExpr. Note that this object represents the `this` pointer, not
// the object that the method is being called on (which is represnted by the
// object from GetInitializedObject()).
Object GetCXXConstructExprThisPointer(
const clang::CXXConstructExpr* expr) const;
// Returns the object associated with, and initialized by, a constructor call
// (CXXConstructExpr) or a initializer list (CXXInitListExpr). Note that this
// represents the actual class object being initialized, not the `this`
// pointer to it that is passed to methods of the class, and which is
// represented by the object from GetCXXConstructExprThisPointer().
Object GetInitializedObject(const clang::Expr* initializer_expr) const;
// Returns what kind of values the given object represents.
ObjectValueType GetObjectValueType(Object object) const;
// Returns the object that represents `*this`, if in a member function.
std::optional<Object> GetThisObject() const {
if (this_object_) {
return **this_object_;
} else {
return std::nullopt;
}
}
// Returns the `Object` associated with the return value of the function.
// Unlike the `Object`s for variables, the "return value object" is a fiction
// -- there is not, in general, going to be a single object associated with
// the return value, and it will not, in general, be possible to take the
// address of the return value object. It's still a useful fiction, however,
// because it allows us to treat return values the same way as other values.
Object GetReturnObject() const { return *return_object_; }
// Returns the object associated with a given field in the struct
// represented by `struct_object`.
const Object* GetFieldObject(Object struct_object,
const clang::FieldDecl* field) const;
// Returns the objects associated with a given field in the structs
// represented by `struct_objects`.
ObjectSet GetFieldObject(const ObjectSet& struct_objects,
const clang::FieldDecl* field) const;
// Returns FieldObjects; useful for producing debugging output.
const FieldObjects& GetFieldObjects() const { return field_object_map_; }
// Returns the object associated with a given base of the struct
// represented by `struct_object`.
const Object* GetBaseClassObject(Object struct_object,
const clang::Type* base) const;
const Object* GetBaseClassObject(Object struct_object,
const clang::QualType base) const {
return GetBaseClassObject(struct_object, base.getTypePtr());
}
// Returns the objects associated with a given base of the structs
// represented by `struct_object`.
ObjectSet GetBaseClassObject(const ObjectSet& struct_objects,
const clang::Type* base) const;
// Returns BaseObjects; useful for producing debugging output.
const BaseObjects& GetBaseObjects() const { return base_object_map_; }
// Returns the PointsToMap implied by variable declarations, i.e. assuming
// that no code has been executed yet.
const PointsToMap& InitialPointsToMap() const {
return initial_points_to_map_;
}
// Creates and returns an object with static lifetime of the given type.
// Also creates any transitive objects if required.
// When called multiple times with the same `type`, this function always
// returns the same object. This is to guarantee that the number of objects
// used in the analysis is bounded and that therefore the lattice is finite
// and the analysis terminates.
Object CreateStaticObject(clang::QualType type);
private:
void CreateObjects(Object root_object, clang::QualType type,
LifetimeFactory lifetime_factory, bool transitive);
const Object* CloneObject(const Object* object);
std::optional<const Object*> GetFieldObjectInternal(
Object struct_object, const clang::FieldDecl* field) const;
llvm::SpecificBumpPtrAllocator<Object> object_allocator_;
// Map from each variable declaration to the object which it declares.
MapType object_repository_;
// Map from each materialized temporary to the object which it declares.
llvm::DenseMap<const clang::MaterializeTemporaryExpr*, const Object*>
temporary_objects_;
// Map from each function parameter to an object representing its initial
// value at function entry.
llvm::DenseMap<const clang::ParmVarDecl*, const Object*>
initial_parameter_object_;
// Map from each initializer (constructors or initializer lists) to the object
// which it initializes.
//
// An object in this map may occur in other places too: `object_repository_`
// if it is an lvalue, or `return_object_`. Or it may be a temporary in which
// case it is only found in this map.
llvm::DenseMap<const clang::Expr*, const Object*> initialized_objects_;
std::optional<const Object*> this_object_;
const Object* return_object_;
llvm::DenseMap<Object, ObjectValueType> object_value_types_;
class VarDeclVisitor;
PointsToMap initial_points_to_map_;
FieldObjects field_object_map_;
BaseObjects base_object_map_;
llvm::DenseMap<std::pair<const clang::Expr*, size_t>, const Object*>
call_expr_args_objects_;
llvm::DenseMap<const clang::Expr*, const Object*> call_expr_this_pointers_;
llvm::DenseMap<clang::QualType, const Object*> static_objects_;
};
} // namespace lifetimes
} // namespace tidy
} // namespace clang
#endif // DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_