Skip to content

Commit ce0c999

Browse files
Googlercopybara-github
authored andcommitted
Reuse CachedConstAccessorsLattice for pointer nullability lattice
The functionality in the pointer nullability lattice was extracted into CachedConstAccessorsLattice for reuse in llvm/llvm-project#111006 . So it should be the same, except for some names (get$X vs getOrCreate$X), and a callback for initializing a StorageLocation if created by getOrCreate$X. Perhaps in the future more can be abstracted into the base dataflow transfer functions. PiperOrigin-RevId: 697632107 Change-Id: Ibfcaa741b86ff85352c9abc9901034a8ac47c035
1 parent 9822f60 commit ce0c999

File tree

5 files changed

+34
-155
lines changed

5 files changed

+34
-155
lines changed

bazel/llvm.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def _llvm_loader_repository(repository_ctx):
5353
executable = False,
5454
)
5555

56-
LLVM_COMMIT_SHA = "b3134fa2338388adf8cfb2d77339d0b042eab9f6"
56+
LLVM_COMMIT_SHA = "64c455077abe583f96fc19398712da9c1187ad61"
5757

5858
def llvm_loader_repository_dependencies():
5959
# This *declares* the dependency, but it won't actually be *downloaded* unless it's used.

nullability/pointer_nullability_analysis.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,8 +1257,15 @@ void handleConstMemberCall(
12571257
// treatment is different from booleans or raw pointers, which are
12581258
// represented as Values.
12591259
if (RecordLoc != nullptr && isSupportedSmartPointerType(CE->getType())) {
1260-
StorageLocation *Loc = State.Lattice.getConstMethodReturnStorageLocation(
1261-
*RecordLoc, CE, State.Env);
1260+
StorageLocation *Loc =
1261+
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
1262+
*RecordLoc, CE, State.Env, [&](StorageLocation &Loc) {
1263+
setSmartPointerValue(
1264+
cast<RecordStorageLocation>(Loc),
1265+
cast<PointerValue>(State.Env.createValue(
1266+
underlyingRawPointerType(CE->getType()))),
1267+
State.Env);
1268+
});
12621269
if (Loc == nullptr) return;
12631270

12641271
if (CE->isGLValue()) {
@@ -1281,8 +1288,8 @@ void handleConstMemberCall(
12811288
if (RecordLoc != nullptr && CE->isPRValue() &&
12821289
(isSupportedRawPointerType(CE->getType()) ||
12831290
CE->getType()->isBooleanType())) {
1284-
Value *Val =
1285-
State.Lattice.getConstMethodReturnValue(*RecordLoc, CE, State.Env);
1291+
Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, CE,
1292+
State.Env);
12861293
if (Val == nullptr) return;
12871294

12881295
State.Env.setValue(*CE, *Val);

nullability/pointer_nullability_lattice.cc

Lines changed: 6 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,17 @@
1010

1111
#include "absl/base/nullability.h"
1212
#include "absl/log/check.h"
13-
#include "nullability/pointer_nullability.h"
1413
#include "nullability/type_nullability.h"
1514
#include "clang/AST/Decl.h"
1615
#include "clang/AST/DeclBase.h"
1716
#include "clang/AST/Expr.h"
18-
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
19-
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
2017
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
21-
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
22-
#include "clang/Analysis/FlowSensitive/Value.h"
2318
#include "clang/Basic/LLVM.h"
24-
#include "llvm/ADT/DenseMap.h"
2519

2620
namespace clang::tidy::nullability {
2721
namespace {
2822

2923
using dataflow::LatticeJoinEffect;
30-
using dataflow::PointerValue;
31-
using dataflow::RecordStorageLocation;
32-
using dataflow::StorageLocation;
33-
using dataflow::Value;
3424

3525
// Returns overridden nullability information associated with a declaration.
3626
// For now we only track top-level decl nullability symbolically and check for
@@ -49,43 +39,10 @@ absl::Nullable<const PointerTypeNullability *> getDeclNullability(
4939
return nullptr;
5040
}
5141

52-
template <typename T>
53-
llvm::SmallDenseMap<const dataflow::RecordStorageLocation *,
54-
llvm::SmallDenseMap<const FunctionDecl *, T *>>
55-
joinConstMethodMap(
56-
const llvm::SmallDenseMap<const dataflow::RecordStorageLocation *,
57-
llvm::SmallDenseMap<const FunctionDecl *, T *>>
58-
&Map1,
59-
const llvm::SmallDenseMap<const dataflow::RecordStorageLocation *,
60-
llvm::SmallDenseMap<const FunctionDecl *, T *>>
61-
&Map2,
62-
LatticeJoinEffect &Effect) {
63-
llvm::SmallDenseMap<const dataflow::RecordStorageLocation *,
64-
llvm::SmallDenseMap<const FunctionDecl *, T *>>
65-
Result;
66-
for (auto &[Loc, DeclToT] : Map1) {
67-
auto It = Map2.find(Loc);
68-
if (It == Map2.end()) {
69-
Effect = LatticeJoinEffect::Changed;
70-
continue;
71-
}
72-
const auto &OtherDeclToT = It->second;
73-
auto &JoinedDeclToT = Result[Loc];
74-
for (auto [Func, Var] : DeclToT) {
75-
T *OtherVar = OtherDeclToT.lookup(Func);
76-
if (OtherVar == nullptr || OtherVar != Var) {
77-
Effect = LatticeJoinEffect::Changed;
78-
continue;
79-
}
80-
JoinedDeclToT.insert({Func, Var});
81-
}
82-
}
83-
return Result;
84-
}
85-
8642
} // namespace
8743

88-
const TypeNullability &PointerNullabilityLattice::insertExprNullabilityIfAbsent(
44+
const TypeNullability &
45+
PointerNullabilityLatticeBase::insertExprNullabilityIfAbsent(
8946
absl::Nonnull<const Expr *> E,
9047
const std::function<TypeNullability()> &GetNullability) {
9148
E = &dataflow::ignoreCFGOmittedNodes(*E);
@@ -100,41 +57,7 @@ const TypeNullability &PointerNullabilityLattice::insertExprNullabilityIfAbsent(
10057
return Iterator->second;
10158
}
10259

103-
absl::Nullable<dataflow::Value *>
104-
PointerNullabilityLattice::getConstMethodReturnValue(
105-
const dataflow::RecordStorageLocation &RecordLoc,
106-
absl::Nonnull<const CallExpr *> CE, dataflow::Environment &Env) {
107-
assert(CE->getType()->isPointerType() || CE->getType()->isBooleanType());
108-
auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
109-
const FunctionDecl *DirectCallee = CE->getDirectCallee();
110-
if (DirectCallee == nullptr) return nullptr;
111-
auto it = ObjMap.find(DirectCallee);
112-
if (it != ObjMap.end()) return it->second;
113-
dataflow::Value *Val = Env.createValue(CE->getType());
114-
if (Val != nullptr) ObjMap.insert({DirectCallee, Val});
115-
return Val;
116-
}
117-
118-
absl::Nullable<dataflow::StorageLocation *>
119-
PointerNullabilityLattice::getConstMethodReturnStorageLocation(
120-
const dataflow::RecordStorageLocation &RecordLoc,
121-
absl::Nonnull<const CallExpr *> CE, dataflow::Environment &Env) {
122-
assert(isSupportedSmartPointerType(CE->getType()));
123-
auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
124-
const FunctionDecl *DirectCallee = CE->getDirectCallee();
125-
if (DirectCallee == nullptr) return nullptr;
126-
auto it = ObjMap.find(DirectCallee);
127-
if (it != ObjMap.end()) return it->second;
128-
StorageLocation &Loc = Env.createStorageLocation(CE->getType());
129-
setSmartPointerValue(cast<RecordStorageLocation>(Loc),
130-
cast<PointerValue>(Env.createValue(
131-
underlyingRawPointerType(CE->getType()))),
132-
Env);
133-
ObjMap.insert({DirectCallee, &Loc});
134-
return &Loc;
135-
}
136-
137-
void PointerNullabilityLattice::overrideNullabilityFromDecl(
60+
void PointerNullabilityLatticeBase::overrideNullabilityFromDecl(
13861
absl::Nullable<const Decl *> D, TypeNullability &N) const {
13962
// For now, overrides are always for pointer values only, and override only
14063
// the top-level nullability.
@@ -144,22 +67,9 @@ void PointerNullabilityLattice::overrideNullabilityFromDecl(
14467
}
14568
}
14669

147-
LatticeJoinEffect PointerNullabilityLattice::join(
148-
const PointerNullabilityLattice &Other) {
149-
// For simplicity, we only retain values that are identical, but not ones that
150-
// are non-identical but equivalent. This is likely to be sufficient in
151-
// practice, and it reduces implementation complexity considerably.
152-
153-
LatticeJoinEffect Effect = LatticeJoinEffect::Unchanged;
154-
ConstMethodReturnValues = joinConstMethodMap<Value>(
155-
ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);
156-
;
157-
158-
ConstMethodReturnStorageLocations = joinConstMethodMap<StorageLocation>(
159-
ConstMethodReturnStorageLocations,
160-
Other.ConstMethodReturnStorageLocations, Effect);
161-
162-
return Effect;
70+
LatticeJoinEffect PointerNullabilityLatticeBase::join(
71+
const PointerNullabilityLatticeBase &Other) {
72+
return LatticeJoinEffect::Unchanged;
16373
}
16474

16575
} // namespace clang::tidy::nullability

nullability/pointer_nullability_lattice.h

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,15 @@
1111

1212
#include "absl/base/nullability.h"
1313
#include "absl/container/flat_hash_map.h"
14-
#include "absl/log/check.h"
1514
#include "nullability/type_nullability.h"
16-
#include "clang/AST/DeclCXX.h"
1715
#include "clang/AST/Expr.h"
18-
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
19-
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16+
#include "clang/Analysis/FlowSensitive/ASTOps.h"
17+
#include "clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h"
2018
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
21-
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
22-
#include "clang/Analysis/FlowSensitive/Value.h"
23-
#include "clang/Basic/LLVM.h"
2419
#include "llvm/ADT/FunctionExtras.h"
2520

2621
namespace clang::tidy::nullability {
27-
class PointerNullabilityLattice {
22+
class PointerNullabilityLatticeBase {
2823
public:
2924
struct NonFlowSensitiveState {
3025
// Nullability interpretation of types as set e.g. by per-file #pragmas.
@@ -46,7 +41,7 @@ class PointerNullabilityLattice {
4641
ConcreteNullabilityOverride = [](const Decl &) { return std::nullopt; };
4742
};
4843

49-
PointerNullabilityLattice(NonFlowSensitiveState &NFS) : NFS(NFS) {}
44+
PointerNullabilityLatticeBase(NonFlowSensitiveState &NFS) : NFS(NFS) {}
5045

5146
absl::Nullable<const TypeNullability *> getTypeNullability(
5247
absl::Nonnull<const Expr *> E) const {
@@ -62,65 +57,31 @@ class PointerNullabilityLattice {
6257
absl::Nonnull<const Expr *> E,
6358
const std::function<TypeNullability()> &GetNullability);
6459

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(
69-
const dataflow::RecordStorageLocation &RecordLoc,
70-
absl::Nonnull<const CallExpr *> CE, dataflow::Environment &Env);
71-
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-
80-
void clearConstMethodReturnValues(
81-
const dataflow::RecordStorageLocation &RecordLoc) {
82-
ConstMethodReturnValues.erase(&RecordLoc);
83-
}
84-
85-
void clearConstMethodReturnStorageLocations(
86-
const dataflow::RecordStorageLocation &RecordLoc) {
87-
ConstMethodReturnStorageLocations.erase(&RecordLoc);
88-
}
89-
9060
// If nullability for the decl D has been overridden, patch N to reflect it.
9161
// (N is the nullability of an access to D).
9262
void overrideNullabilityFromDecl(absl::Nullable<const Decl *> D,
9363
TypeNullability &N) const;
9464

95-
bool operator==(const PointerNullabilityLattice &Other) const { return true; }
65+
bool operator==(const PointerNullabilityLatticeBase &Other) const {
66+
return true;
67+
}
9668

97-
dataflow::LatticeJoinEffect join(const PointerNullabilityLattice &Other);
69+
dataflow::LatticeJoinEffect join(const PointerNullabilityLatticeBase &Other);
9870

9971
const TypeNullabilityDefaults &defaults() const { return NFS.Defaults; }
10072

10173
private:
10274
// Owned by the PointerNullabilityAnalysis object, shared by all lattice
10375
// elements within one analysis run.
10476
NonFlowSensitiveState &NFS;
105-
106-
// Maps a record storage location and const method to the value to return
107-
// from that const method.
108-
using ConstMethodReturnValuesType = llvm::SmallDenseMap<
109-
const dataflow::RecordStorageLocation *,
110-
llvm::SmallDenseMap<const FunctionDecl *, dataflow::Value *>>;
111-
ConstMethodReturnValuesType ConstMethodReturnValues;
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;
11977
};
12078

79+
using PointerNullabilityLattice =
80+
dataflow::CachedConstAccessorsLattice<PointerNullabilityLatticeBase>;
81+
12182
inline std::ostream &operator<<(std::ostream &OS,
12283
const PointerNullabilityLattice &) {
123-
return OS << "noop";
84+
return OS << "nullability";
12485
}
12586

12687
} // namespace clang::tidy::nullability

nullability/pointer_nullability_lattice_test.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,14 @@ TEST_F(PointerNullabilityLatticeTest, ConstMethodProducesNewValueAfterJoin) {
7878
RecordStorageLocation Loc(SType, RecordStorageLocation::FieldToLoc(), {});
7979

8080
PointerNullabilityLattice Lattice1(NFS);
81-
Value *Val1 = Lattice1.getConstMethodReturnValue(Loc, CE, Env);
81+
Value *Val1 = Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);
8282

8383
PointerNullabilityLattice Lattice2(NFS);
84-
Value *Val2 = Lattice2.getConstMethodReturnValue(Loc, CE, Env);
84+
Value *Val2 = Lattice2.getOrCreateConstMethodReturnValue(Loc, CE, Env);
8585

8686
EXPECT_EQ(Lattice1.join(Lattice2), LatticeJoinEffect::Changed);
87-
Value *ValAfterJoin = Lattice1.getConstMethodReturnValue(Loc, CE, Env);
87+
Value *ValAfterJoin =
88+
Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);
8889

8990
EXPECT_NE(ValAfterJoin, Val1);
9091
EXPECT_NE(ValAfterJoin, Val2);

0 commit comments

Comments
 (0)