Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | |
| 5 | #ifndef DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |
| 6 | #define DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |
| 7 | |
| 8 | #include <functional> |
| 9 | #include <optional> |
| 10 | #include <string> |
| 11 | #include <variant> |
| 12 | |
| 13 | #include "lifetime_analysis/object.h" |
| 14 | #include "lifetime_analysis/object_set.h" |
| 15 | #include "lifetime_analysis/points_to_map.h" |
| 16 | #include "lifetime_annotations/type_lifetimes.h" |
| 17 | #include "clang/AST/Decl.h" |
| 18 | #include "clang/AST/Expr.h" |
| 19 | #include "clang/AST/ExprCXX.h" |
| 20 | #include "llvm/ADT/DenseMap.h" |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 21 | #include "llvm/Support/Allocator.h" |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 22 | |
| 23 | namespace clang { |
| 24 | namespace tidy { |
| 25 | namespace lifetimes { |
| 26 | |
| 27 | // A record-type expression has 2 modes: |
| 28 | // 1. If it's being assigned to a reference, then the contents of the expression |
| 29 | // are a glvalue. This is because references require an object to point to. |
| 30 | // 2. If it's being assigned to a record object, then the expression itself is |
| 31 | // not creating an object, but initializing it. So the expression's type is |
| 32 | // a pure value, and it acts _on_ the initializing object instead of |
| 33 | // producing an object. |
| 34 | inline bool IsInitExprInitializingARecordObject(const clang::Expr* expr) { |
| 35 | return expr->getType()->isRecordType() && expr->isPRValue(); |
| 36 | } |
| 37 | |
| 38 | // A repository for the objects used in the lifetime analysis of a single |
| 39 | // function. |
Martin Brænne | fb8153d | 2022-06-28 04:05:14 -0700 | [diff] [blame] | 40 | // This class establishes a relationship between AST nodes (e.g. variable |
| 41 | // declarations) and the objects that represent them. It also stores additional |
| 42 | // information about objects that does not change during the analysis. |
| 43 | // The `ObjectRepository` only stores state that does not change during the |
| 44 | // analysis; it is therefore not part of the lattice. |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 45 | class ObjectRepository { |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 46 | private: |
| 47 | using MapType = llvm::DenseMap<const clang::ValueDecl*, Object>; |
| 48 | |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 49 | public: |
| 50 | // An `Object` might represent objects that have either a single value (such |
| 51 | // as plain variables) or multiple ones (such as arrays, or structs). |
| 52 | // Assignment behaves differently in the two cases. |
| 53 | enum class ObjectValueType { |
| 54 | kSingleValued, |
| 55 | kMultiValued, |
| 56 | }; |
| 57 | |
| 58 | // Tag struct for InitializedObject: the object being initialized is the |
| 59 | // return value of the function. |
| 60 | struct ReturnValue {}; |
| 61 | |
| 62 | // Maps a given struct-Object to the Object for each of its fields. |
| 63 | // TODO(veluca): this approach does not produce correct results when |
| 64 | // diamond-problem-style multiple inheritance happens. |
| 65 | using FieldObjects = |
| 66 | llvm::DenseMap<std::pair<Object, const clang::FieldDecl*>, Object>; |
| 67 | |
| 68 | // Maps a given struct-Object to the Object for each of its bases. |
| 69 | using BaseObjects = |
| 70 | llvm::DenseMap<std::pair<Object, const clang::Type*>, Object>; |
| 71 | |
Martin Brænne | d7f2009 | 2022-06-28 04:04:33 -0700 | [diff] [blame] | 72 | // Iterator refers to a pair consisting of a variable declaration and the |
| 73 | // object representing that variable. |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 74 | using const_iterator = MapType::const_iterator; |
| 75 | using value_type = MapType::value_type; |
| 76 | |
| 77 | // Initializes the map with objects for all variables that are declared or |
| 78 | // referenced in `func`. |
| 79 | explicit ObjectRepository(const clang::FunctionDecl* func); |
| 80 | |
| 81 | // Move-only. |
| 82 | ObjectRepository(ObjectRepository&&) = default; |
| 83 | ObjectRepository& operator=(ObjectRepository&&) = default; |
| 84 | |
| 85 | // Returns a human-readable representation of the mapping. |
| 86 | std::string DebugString() const; |
| 87 | |
| 88 | const_iterator begin() const { return object_repository_.begin(); } |
| 89 | const_iterator end() const { return object_repository_.end(); } |
| 90 | |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 91 | // Creates an object with the given lifetime and type. |
| 92 | // The returned object will live as long as this `ObjectRepository`. |
| 93 | const Object* CreateObject(Lifetime lifetime, clang::QualType type); |
| 94 | |
| 95 | // Creates an object representing a declared function. |
| 96 | // The returned object will live as long as this `ObjectRepository`. |
| 97 | const Object* CreateObjectFromFunctionDecl(const clang::FunctionDecl& func); |
| 98 | |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 99 | // Returns the object associated with a variable or function. |
| 100 | Object GetDeclObject(const clang::ValueDecl* decl) const; |
| 101 | |
| 102 | // Returns the object associated with a materialize temporary expression. |
| 103 | Object GetTemporaryObject(const clang::MaterializeTemporaryExpr* expr) const; |
| 104 | |
| 105 | // Returns the object representing the value of a function parameter at |
| 106 | // function entry. |
| 107 | // Note: This `Object` does not represent the parameter variable itself; |
| 108 | // use GetDeclObject() to retrieve that. We're using an `Object` here |
| 109 | // because we don't have a dedicated "value" class, but you should not |
| 110 | // use this object's identity in any way; i.e. no other `Object` in the |
| 111 | // points-to map should ever point to the object returned by this |
| 112 | // function. |
| 113 | Object GetOriginalParameterValue(const clang::ParmVarDecl* var_decl) const; |
| 114 | |
| 115 | // Returns the object associated with an argument to a CallExpr. |
| 116 | Object GetCallExprArgumentObject(const clang::CallExpr* expr, |
| 117 | size_t arg_index) const; |
| 118 | |
| 119 | // Returns the object associated with the `this` argument to a CallExpr that |
| 120 | // represents a method call. Note that this object represents the `this` |
| 121 | // pointer, not the object that the method is being called on. |
| 122 | Object GetCallExprThisPointer(const clang::CallExpr* expr) const; |
| 123 | |
| 124 | // Returns the object associated with an argument to a CXXConstructExpr. |
| 125 | Object GetCXXConstructExprArgumentObject(const clang::CXXConstructExpr* expr, |
| 126 | size_t arg_index) const; |
| 127 | |
| 128 | // Returns the object associated with the `this` argument to a |
| 129 | // CXXConstructExpr. Note that this object represents the `this` pointer, not |
| 130 | // the object that the method is being called on (which is represnted by the |
| 131 | // object from GetInitializedObject()). |
| 132 | Object GetCXXConstructExprThisPointer( |
| 133 | const clang::CXXConstructExpr* expr) const; |
| 134 | |
| 135 | // Returns the object associated with, and initialized by, a constructor call |
| 136 | // (CXXConstructExpr) or a initializer list (CXXInitListExpr). Note that this |
| 137 | // represents the actual class object being initialized, not the `this` |
| 138 | // pointer to it that is passed to methods of the class, and which is |
| 139 | // represented by the object from GetCXXConstructExprThisPointer(). |
| 140 | Object GetInitializedObject(const clang::Expr* initializer_expr) const; |
| 141 | |
| 142 | // Returns what kind of values the given object represents. |
| 143 | ObjectValueType GetObjectValueType(Object object) const; |
| 144 | |
| 145 | // Returns the object that represents `*this`, if in a member function. |
Martin Brænne | 04fb3a4 | 2022-07-01 01:52:21 -0700 | [diff] [blame] | 146 | std::optional<Object> GetThisObject() const { |
| 147 | if (this_object_) { |
| 148 | return **this_object_; |
| 149 | } else { |
| 150 | return std::nullopt; |
| 151 | } |
| 152 | } |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 153 | |
| 154 | // Returns the `Object` associated with the return value of the function. |
| 155 | // Unlike the `Object`s for variables, the "return value object" is a fiction |
| 156 | // -- there is not, in general, going to be a single object associated with |
| 157 | // the return value, and it will not, in general, be possible to take the |
| 158 | // address of the return value object. It's still a useful fiction, however, |
| 159 | // because it allows us to treat return values the same way as other values. |
Martin Brænne | 04fb3a4 | 2022-07-01 01:52:21 -0700 | [diff] [blame] | 160 | Object GetReturnObject() const { return *return_object_; } |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 161 | |
| 162 | // Returns the object associated with a given field in the struct |
| 163 | // represented by `struct_object`. |
| 164 | Object GetFieldObject(Object struct_object, |
| 165 | const clang::FieldDecl* field) const; |
| 166 | |
| 167 | // Returns the objects associated with a given field in the structs |
| 168 | // represented by `struct_objects`. |
| 169 | ObjectSet GetFieldObject(const ObjectSet& struct_objects, |
| 170 | const clang::FieldDecl* field) const; |
| 171 | |
| 172 | // Returns FieldObjects; useful for producing debugging output. |
| 173 | const FieldObjects& GetFieldObjects() const { return field_object_map_; } |
| 174 | |
| 175 | // Returns the object associated with a given base of the struct |
| 176 | // represented by `struct_object`. |
| 177 | Object GetBaseClassObject(Object struct_object, |
| 178 | const clang::Type* base) const; |
| 179 | Object GetBaseClassObject(Object struct_object, |
| 180 | const clang::QualType base) const { |
| 181 | return GetBaseClassObject(struct_object, base.getTypePtr()); |
| 182 | } |
| 183 | |
| 184 | // Returns the objects associated with a given base of the structs |
| 185 | // represented by `struct_object`. |
| 186 | ObjectSet GetBaseClassObject(const ObjectSet& struct_objects, |
| 187 | const clang::Type* base) const; |
| 188 | |
| 189 | // Returns BaseObjects; useful for producing debugging output. |
| 190 | const BaseObjects& GetBaseObjects() const { return base_object_map_; } |
| 191 | |
| 192 | // Returns the PointsToMap implied by variable declarations, i.e. assuming |
| 193 | // that no code has been executed yet. |
| 194 | const PointsToMap& InitialPointsToMap() const { |
| 195 | return initial_points_to_map_; |
| 196 | } |
| 197 | |
| 198 | // Creates and returns an object with static lifetime of the given type. |
| 199 | // Also creates any transitive objects if required. |
| 200 | // When called multiple times with the same `type`, this function always |
| 201 | // returns the same object. This is to guarantee that the number of objects |
| 202 | // used in the analysis is bounded and that therefore the lattice is finite |
| 203 | // and the analysis terminates. |
| 204 | Object CreateStaticObject(clang::QualType type); |
| 205 | |
| 206 | private: |
| 207 | void CreateObjects(Object root_object, clang::QualType type, |
| 208 | LifetimeFactory lifetime_factory, bool transitive); |
| 209 | |
| 210 | Object CloneObject(Object object); |
| 211 | |
| 212 | std::optional<Object> GetFieldObjectInternal( |
| 213 | Object struct_object, const clang::FieldDecl* field) const; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 214 | |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 215 | llvm::SpecificBumpPtrAllocator<Object> object_allocator_; |
| 216 | |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 217 | // Map from each variable declaration to the object which it declares. |
| 218 | MapType object_repository_; |
| 219 | |
| 220 | // Map from each materialized temporary to the object which it declares. |
Martin Brænne | 8f8e4fe | 2022-07-01 01:53:28 -0700 | [diff] [blame^] | 221 | llvm::DenseMap<const clang::MaterializeTemporaryExpr*, const Object*> |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 222 | temporary_objects_; |
| 223 | |
| 224 | // Map from each function parameter to an object representing its initial |
| 225 | // value at function entry. |
| 226 | llvm::DenseMap<const clang::ParmVarDecl*, Object> initial_parameter_object_; |
| 227 | |
| 228 | // Map from each initializer (constructors or initializer lists) to the object |
| 229 | // which it initializes. |
| 230 | // |
| 231 | // An object in this map may occur in other places too: `object_repository_` |
| 232 | // if it is an lvalue, or `return_object_`. Or it may be a temporary in which |
| 233 | // case it is only found in this map. |
| 234 | llvm::DenseMap<const clang::Expr*, Object> initialized_objects_; |
| 235 | |
Martin Brænne | 04fb3a4 | 2022-07-01 01:52:21 -0700 | [diff] [blame] | 236 | std::optional<const Object*> this_object_; |
| 237 | const Object* return_object_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 238 | |
| 239 | llvm::DenseMap<Object, ObjectValueType> object_value_types_; |
| 240 | |
| 241 | class VarDeclVisitor; |
| 242 | |
| 243 | PointsToMap initial_points_to_map_; |
| 244 | FieldObjects field_object_map_; |
| 245 | BaseObjects base_object_map_; |
| 246 | |
| 247 | llvm::DenseMap<std::pair<const clang::Expr*, size_t>, Object> |
| 248 | call_expr_args_objects_; |
| 249 | |
| 250 | llvm::DenseMap<const clang::Expr*, Object> call_expr_this_pointers_; |
| 251 | |
| 252 | llvm::DenseMap<clang::QualType, Object> static_objects_; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 253 | }; |
| 254 | |
| 255 | } // namespace lifetimes |
| 256 | } // namespace tidy |
| 257 | } // namespace clang |
| 258 | |
| 259 | #endif // DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |