blob: f8c71f4aeec76fcc41bc389a66a8bed177b002eb [file] [log] [blame]
Wei Yi Tee543af742022-06-01 06:52:24 -07001// 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
Googler7f19b2b2023-05-01 09:44:57 -07005#ifndef CRUBIT_NULLABILITY_POINTER_NULLABILITY_ANALYSIS_H_
6#define CRUBIT_NULLABILITY_POINTER_NULLABILITY_ANALYSIS_H_
Wei Yi Tee543af742022-06-01 06:52:24 -07007
Googler2c9f53f2023-10-24 07:33:00 -07008#include <optional>
Sam McCalle644e1d2023-07-18 19:19:12 -07009#include <utility>
10
Googler7f19b2b2023-05-01 09:44:57 -070011#include "nullability/pointer_nullability_lattice.h"
Sam McCall74bf8642023-06-16 11:21:42 -070012#include "nullability/type_nullability.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070013#include "clang/AST/ASTContext.h"
Sam McCall74bf8642023-06-16 11:21:42 -070014#include "clang/AST/Decl.h"
Googler2c9f53f2023-10-24 07:33:00 -070015#include "clang/AST/DeclBase.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070016#include "clang/AST/Type.h"
Sam McCall74bf8642023-06-16 11:21:42 -070017#include "clang/Analysis/FlowSensitive/Arena.h"
Wei Yi Tee217eb5f2022-09-15 03:18:28 -070018#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070019#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
20#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070021#include "clang/Analysis/FlowSensitive/Value.h"
Googler2c9f53f2023-10-24 07:33:00 -070022#include "llvm/ADT/FunctionExtras.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070023
24namespace clang {
25namespace tidy {
26namespace nullability {
27
Wei Yi Tee8b58e192022-08-02 10:15:40 -070028/// Analyses constructs in the source code to collect nullability information
29/// about pointers at each program point.
Wei Yi Tee543af742022-06-01 06:52:24 -070030class PointerNullabilityAnalysis
31 : public dataflow::DataflowAnalysis<PointerNullabilityAnalysis,
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -080032 PointerNullabilityLattice> {
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -080033 private:
Sam McCall74bf8642023-06-16 11:21:42 -070034 PointerNullabilityLattice::NonFlowSensitiveState NFS;
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -080035
Wei Yi Tee543af742022-06-01 06:52:24 -070036 public:
Sam McCall7d9afee2023-06-27 01:43:24 -070037 explicit PointerNullabilityAnalysis(ASTContext &context);
Wei Yi Tee543af742022-06-01 06:52:24 -070038
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -080039 PointerNullabilityLattice initialElement() {
Sam McCall74bf8642023-06-16 11:21:42 -070040 return PointerNullabilityLattice(NFS);
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -080041 }
Wei Yi Tee543af742022-06-01 06:52:24 -070042
Sam McCall74bf8642023-06-16 11:21:42 -070043 // Instead of fixing D's nullability invariants from its annotations,
44 // bind them to symbolic variables, and return those variables.
45 // This is useful to infer the annotations that should be present on D.
46 //
47 // For example, given the following program:
48 // void target(int* p) {
49 // int* q = p;
50 // *q;
51 // }
52 //
53 // By default, p is treated as having unspecified nullability.
54 // When we reach the dereference, our flow condition will say:
Googler1a55cfb2023-07-17 13:45:18 -070055 // from_nullable = false
Sam McCall74bf8642023-06-16 11:21:42 -070056 //
57 // However, if we bind p's nullability to a variable:
Sam McCalle644e1d2023-07-18 19:19:12 -070058 // pn = assignNullabilityVariable(p)
Sam McCall74bf8642023-06-16 11:21:42 -070059 // Then the flow condition at dereference includes:
Sam McCalle644e1d2023-07-18 19:19:12 -070060 // from_nullable = pn.Nullable
61 // pn.Nonnull => !is_null
Sam McCall74bf8642023-06-16 11:21:42 -070062 // Logically connecting dereferenced values and possible invariants on p
63 // allows us to infer p's proper annotations (here: Nonnull).
64 //
65 // For now, only the top-level nullability is assigned, and the returned
66 // variables are only associated with direct reads of pointer values from D.
Sam McCalle644e1d2023-07-18 19:19:12 -070067 //
68 // The returned nullability is guaranteed to be symbolic.
Sam McCall7d9afee2023-06-27 01:43:24 -070069 PointerTypeNullability assignNullabilityVariable(const ValueDecl *D,
70 dataflow::Arena &);
Sam McCall74bf8642023-06-16 11:21:42 -070071
Googler2c9f53f2023-10-24 07:33:00 -070072 void assignNullabilityOverride(
73 llvm::unique_function<
74 std::optional<const PointerTypeNullability *>(const Decl &) const>
75 Override) {
76 NFS.ConcreteNullabilityOverride = std::move(Override);
77 }
78
Sam McCall7d9afee2023-06-27 01:43:24 -070079 void transfer(const CFGElement &Elt, PointerNullabilityLattice &Lattice,
80 dataflow::Environment &Env);
Wei Yi Tee543af742022-06-01 06:52:24 -070081
Sam McCall7d9afee2023-06-27 01:43:24 -070082 bool merge(QualType Type, const dataflow::Value &Val1,
83 const dataflow::Environment &Env1, const dataflow::Value &Val2,
84 const dataflow::Environment &Env2, dataflow::Value &MergedVal,
85 dataflow::Environment &MergedEnv) override;
Wei Yi Tee543af742022-06-01 06:52:24 -070086
Martin Brænnedd2a7702023-10-26 06:57:18 -070087 dataflow::ComparisonResult compare(
88 QualType Type, const dataflow::Value &Val1,
89 const dataflow::Environment &Env1, const dataflow::Value &Val2,
90 const dataflow::Environment &Env2) override;
91
92 dataflow::Value *widen(QualType Type, dataflow::Value &Prev,
93 const dataflow::Environment &PrevEnv,
94 dataflow::Value &Current,
95 dataflow::Environment &CurrentEnv) override;
96
Wei Yi Tee543af742022-06-01 06:52:24 -070097 private:
Martin Brænnedd2a7702023-10-26 06:57:18 -070098 // Returns a storage location representing "top", i.e. a storage location of
99 // type `Ty` about which nothing else is known.
100 // Known limitation: We can't prevent a "top" storage location from being
101 // associated with a value. This is somewhat strange but does not appear to
102 // have any ill effects in practice. To disallow this, we may at some point
103 // want to move the concept of "top" storage locations to the framework.
104 dataflow::StorageLocation &getTopStorageLocation(
105 dataflow::DataflowAnalysisContext &DACtx, QualType Ty);
106
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800107 // Applies non-flow-sensitive transfer functions on statements
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800108 dataflow::CFGMatchSwitch<dataflow::TransferState<PointerNullabilityLattice>>
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800109 NonFlowSensitiveTransferer;
110
111 // Applies flow-sensitive transfer functions on statements
112 dataflow::CFGMatchSwitch<dataflow::TransferState<PointerNullabilityLattice>>
113 FlowSensitiveTransferer;
Martin Brænnedd2a7702023-10-26 06:57:18 -0700114
115 // Storage locations that represent "top" for each given type.
116 llvm::DenseMap<QualType, dataflow::StorageLocation *> TopStorageLocations;
Wei Yi Tee543af742022-06-01 06:52:24 -0700117};
118} // namespace nullability
119} // namespace tidy
120} // namespace clang
121
Googler7f19b2b2023-05-01 09:44:57 -0700122#endif // CRUBIT_NULLABILITY_POINTER_NULLABILITY_ANALYSIS_H_