Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [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 | |
Sam McCall | da39880 | 2023-06-27 01:57:22 -0700 | [diff] [blame] | 5 | #ifndef CRUBIT_NULLABILITY_POINTER_NULLABILITY_LATTICE_H_ |
| 6 | #define CRUBIT_NULLABILITY_POINTER_NULLABILITY_LATTICE_H_ |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 7 | |
Dmitri Gribenko | 742c4c3 | 2023-07-31 12:32:09 -0700 | [diff] [blame] | 8 | #include <functional> |
Googler | 2c9f53f | 2023-10-24 07:33:00 -0700 | [diff] [blame] | 9 | #include <optional> |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 10 | #include <ostream> |
| 11 | |
Googler | f7154ea | 2023-12-11 09:30:25 -0800 | [diff] [blame] | 12 | #include "absl/base/nullability.h" |
Dani Ferreira Franco Moura | 97f5c61 | 2022-12-17 13:28:24 -0800 | [diff] [blame] | 13 | #include "absl/container/flat_hash_map.h" |
Googler | d443731 | 2023-01-17 15:10:29 -0800 | [diff] [blame] | 14 | #include "absl/log/check.h" |
Sam McCall | d127f93 | 2023-05-02 07:15:27 -0700 | [diff] [blame] | 15 | #include "nullability/type_nullability.h" |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 16 | #include "clang/AST/DeclCXX.h" |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 17 | #include "clang/AST/Expr.h" |
Dani Ferreira Franco Moura | 0d0db1d | 2023-01-17 11:08:07 -0800 | [diff] [blame] | 18 | #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 19 | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 20 | #include "clang/Analysis/FlowSensitive/DataflowLattice.h" |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 21 | #include "clang/Analysis/FlowSensitive/StorageLocation.h" |
| 22 | #include "clang/Analysis/FlowSensitive/Value.h" |
Googler | 2c9f53f | 2023-10-24 07:33:00 -0700 | [diff] [blame] | 23 | #include "clang/Basic/LLVM.h" |
| 24 | #include "llvm/ADT/FunctionExtras.h" |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 25 | |
Sam McCall | 4f6be42 | 2023-06-27 02:51:22 -0700 | [diff] [blame] | 26 | namespace clang::tidy::nullability { |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 27 | class PointerNullabilityLattice { |
| 28 | public: |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 29 | struct NonFlowSensitiveState { |
Sam McCall | c290df4 | 2024-04-02 11:28:44 -0700 | [diff] [blame] | 30 | // Nullability interpretation of types as set e.g. by per-file #pragmas. |
| 31 | TypeNullabilityDefaults Defaults; |
| 32 | |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 33 | absl::flat_hash_map<const Expr *, TypeNullability> ExprToNullability; |
| 34 | // Overridden symbolic nullability for pointer-typed decls. |
Sam McCall | e644e1d | 2023-07-18 19:19:12 -0700 | [diff] [blame] | 35 | // These are set by PointerNullabilityAnalysis::assignNullabilityVariable, |
Googler | 2c9f53f | 2023-10-24 07:33:00 -0700 | [diff] [blame] | 36 | // and take precedence over the declared type and over any result from |
| 37 | // ConcreteNullabilityOverride. |
Googler | f7154ea | 2023-12-11 09:30:25 -0800 | [diff] [blame] | 38 | absl::flat_hash_map<absl::Nonnull<const ValueDecl *>, |
| 39 | PointerTypeNullability> |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 40 | DeclTopLevelNullability; |
Googler | 2c9f53f | 2023-10-24 07:33:00 -0700 | [diff] [blame] | 41 | // Returns overriding concrete nullability for decls. This is set by |
| 42 | // PointerNullabilityAnalysis::assignNullabilityOverride, and the result, if |
| 43 | // present, takes precedence over the declared type. |
| 44 | llvm::unique_function<std::optional<const PointerTypeNullability *>( |
| 45 | const Decl &) const> |
| 46 | ConcreteNullabilityOverride = [](const Decl &) { return std::nullopt; }; |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 47 | }; |
| 48 | |
| 49 | PointerNullabilityLattice(NonFlowSensitiveState &NFS) : NFS(NFS) {} |
Dani Ferreira Franco Moura | 97f5c61 | 2022-12-17 13:28:24 -0800 | [diff] [blame] | 50 | |
Martin Brænne | c92447f | 2024-06-04 13:17:06 -0700 | [diff] [blame] | 51 | absl::Nullable<const TypeNullability *> getTypeNullability( |
Googler | f7154ea | 2023-12-11 09:30:25 -0800 | [diff] [blame] | 52 | absl::Nonnull<const Expr *> E) const { |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 53 | auto I = NFS.ExprToNullability.find(&dataflow::ignoreCFGOmittedNodes(*E)); |
| 54 | return I == NFS.ExprToNullability.end() ? nullptr : &I->second; |
Dani Ferreira Franco Moura | 97f5c61 | 2022-12-17 13:28:24 -0800 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | // If the `ExprToNullability` map already contains an entry for `E`, does |
| 58 | // nothing. Otherwise, inserts a new entry with key `E` and value computed by |
| 59 | // the provided GetNullability. |
Googler | d443731 | 2023-01-17 15:10:29 -0800 | [diff] [blame] | 60 | // Returns the (cached or computed) nullability. |
Sam McCall | d127f93 | 2023-05-02 07:15:27 -0700 | [diff] [blame] | 61 | const TypeNullability &insertExprNullabilityIfAbsent( |
Googler | f7154ea | 2023-12-11 09:30:25 -0800 | [diff] [blame] | 62 | absl::Nonnull<const Expr *> E, |
Martin Brænne | 93db865 | 2024-02-28 01:59:48 -0800 | [diff] [blame] | 63 | const std::function<TypeNullability()> &GetNullability); |
Dani Ferreira Franco Moura | 97f5c61 | 2022-12-17 13:28:24 -0800 | [diff] [blame] | 64 | |
Martin Brænne | dd03ae8 | 2024-03-28 08:02:41 -0700 | [diff] [blame] | 65 | // Returns the `Value` associated with the `RecordStorageLocation` and |
| 66 | // `MethodDecl` of `CE`, creating one if it doesn't yet exist. |
| 67 | // The type of `CE` must be either a raw pointer or boolean. |
| 68 | absl::Nullable<dataflow::Value *> getConstMethodReturnValue( |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 69 | const dataflow::RecordStorageLocation &RecordLoc, |
Martin Brænne | 93db865 | 2024-02-28 01:59:48 -0800 | [diff] [blame] | 70 | absl::Nonnull<const CallExpr *> CE, dataflow::Environment &Env); |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 71 | |
Googler | d54739c | 2024-07-31 09:24:46 -0700 | [diff] [blame] | 72 | // Returns the `RecordStorageLocation` associated with the |
| 73 | // `RecordStorageLocation` and `MethodDecl` of `CE`, creating one if it |
| 74 | // doesn't yet exist. The type of `CE` must be a smart pointer. |
| 75 | absl::Nullable<dataflow::StorageLocation *> |
| 76 | getConstMethodReturnStorageLocation( |
| 77 | const dataflow::RecordStorageLocation &RecordLoc, |
| 78 | absl::Nonnull<const CallExpr *> CE, dataflow::Environment &Env); |
| 79 | |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 80 | void clearConstMethodReturnValues( |
| 81 | const dataflow::RecordStorageLocation &RecordLoc) { |
| 82 | ConstMethodReturnValues.erase(&RecordLoc); |
| 83 | } |
| 84 | |
Googler | d54739c | 2024-07-31 09:24:46 -0700 | [diff] [blame] | 85 | void clearConstMethodReturnStorageLocations( |
| 86 | const dataflow::RecordStorageLocation &RecordLoc) { |
| 87 | ConstMethodReturnStorageLocations.erase(&RecordLoc); |
| 88 | } |
| 89 | |
Googler | 0b222ba | 2023-11-03 08:02:58 -0700 | [diff] [blame] | 90 | // If nullability for the decl D has been overridden, patch N to reflect it. |
| 91 | // (N is the nullability of an access to D). |
Googler | f7154ea | 2023-12-11 09:30:25 -0800 | [diff] [blame] | 92 | void overrideNullabilityFromDecl(absl::Nullable<const Decl *> D, |
| 93 | TypeNullability &N) const; |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 94 | |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 95 | bool operator==(const PointerNullabilityLattice &Other) const { return true; } |
| 96 | |
Martin Brænne | 0a9f509 | 2024-03-28 07:54:25 -0700 | [diff] [blame] | 97 | dataflow::LatticeJoinEffect join(const PointerNullabilityLattice &Other); |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 98 | |
Sam McCall | c290df4 | 2024-04-02 11:28:44 -0700 | [diff] [blame] | 99 | const TypeNullabilityDefaults &defaults() const { return NFS.Defaults; } |
| 100 | |
Sam McCall | 74bf864 | 2023-06-16 11:21:42 -0700 | [diff] [blame] | 101 | private: |
| 102 | // Owned by the PointerNullabilityAnalysis object, shared by all lattice |
| 103 | // elements within one analysis run. |
| 104 | NonFlowSensitiveState &NFS; |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 105 | |
| 106 | // Maps a record storage location and const method to the value to return |
| 107 | // from that const method. |
Martin Brænne | 0a9f509 | 2024-03-28 07:54:25 -0700 | [diff] [blame] | 108 | using ConstMethodReturnValuesType = llvm::SmallDenseMap< |
Googler | ca74c79 | 2023-11-08 11:27:22 -0800 | [diff] [blame] | 109 | const dataflow::RecordStorageLocation *, |
Martin Brænne | dd03ae8 | 2024-03-28 08:02:41 -0700 | [diff] [blame] | 110 | llvm::SmallDenseMap<const FunctionDecl *, dataflow::Value *>>; |
Martin Brænne | 0a9f509 | 2024-03-28 07:54:25 -0700 | [diff] [blame] | 111 | ConstMethodReturnValuesType ConstMethodReturnValues; |
Googler | d54739c | 2024-07-31 09:24:46 -0700 | [diff] [blame] | 112 | |
| 113 | // Maps a record storage location and const method to the record storage |
| 114 | // location to return from that const method. |
| 115 | using ConstMethodReturnStorageLocationsType = llvm::SmallDenseMap< |
| 116 | const dataflow::RecordStorageLocation *, |
| 117 | llvm::SmallDenseMap<const FunctionDecl *, dataflow::StorageLocation *>>; |
| 118 | ConstMethodReturnStorageLocationsType ConstMethodReturnStorageLocations; |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 119 | }; |
| 120 | |
| 121 | inline std::ostream &operator<<(std::ostream &OS, |
| 122 | const PointerNullabilityLattice &) { |
| 123 | return OS << "noop"; |
| 124 | } |
| 125 | |
Sam McCall | 4f6be42 | 2023-06-27 02:51:22 -0700 | [diff] [blame] | 126 | } // namespace clang::tidy::nullability |
Dani Ferreira Franco Moura | 3d56a22 | 2022-11-29 03:12:55 -0800 | [diff] [blame] | 127 | |
Sam McCall | da39880 | 2023-06-27 01:57:22 -0700 | [diff] [blame] | 128 | #endif // CRUBIT_NULLABILITY_POINTER_NULLABILITY_LATTICE_H_ |