Implement transfer function for identifying `this` pointer as always non-null.
PiperOrigin-RevId: 454134063
diff --git a/nullability_verification/pointer_nullability_analysis.cc b/nullability_verification/pointer_nullability_analysis.cc
index a512ec4..0745567 100644
--- a/nullability_verification/pointer_nullability_analysis.cc
+++ b/nullability_verification/pointer_nullability_analysis.cc
@@ -44,20 +44,29 @@
}
void initialisePointerNotNullProperty(
- const Expr* PointerExpr, TransferState<PointerNullabilityLattice>& State) {
+ const Expr* PointerExpr, TransferState<PointerNullabilityLattice>& State,
+ BoolValue* NotNullProperty = nullptr) {
if (auto* PointerVal = cast_or_null<PointerValue>(
State.Env.getValue(*PointerExpr, SkipPast::Reference))) {
if (!State.Lattice.hasPointerNotNullProperty(PointerVal)) {
- State.Lattice.setPointerNotNullProperty(PointerVal,
- &State.Env.makeAtomicBoolValue());
+ State.Lattice.setPointerNotNullProperty(
+ PointerVal,
+ NotNullProperty ? NotNullProperty : &State.Env.makeAtomicBoolValue());
}
}
}
void transferInitPointerVariableReference(
- const Expr* Expr, const MatchFinder::MatchResult&,
+ const Expr* PointerExpr, const MatchFinder::MatchResult&,
TransferState<PointerNullabilityLattice>& State) {
- initialisePointerNotNullProperty(Expr, State);
+ initialisePointerNotNullProperty(PointerExpr, State);
+}
+
+void transferInitCXXThisExpr(const Expr* ThisExpr,
+ const MatchFinder::MatchResult&,
+ TransferState<PointerNullabilityLattice>& State) {
+ initialisePointerNotNullProperty(ThisExpr, State,
+ &State.Env.getBoolLiteralValue(true));
}
void transferNullPointerLiteral(
@@ -167,6 +176,7 @@
// Handles initialization of the null states of pointers
.CaseOf<Expr>(isPointerVariableReference(),
transferInitPointerVariableReference)
+ .CaseOf<Expr>(isCXXThisExpr(), transferInitCXXThisExpr)
// Handles initialization of null states of member pointers and safety of
// member access (->) on pointers
.CaseOf<MemberExpr>(isMemberExprInvolvingPointers(),
diff --git a/nullability_verification/pointer_nullability_analysis_test.cc b/nullability_verification/pointer_nullability_analysis_test.cc
index d8c66d4..77f64bf 100644
--- a/nullability_verification/pointer_nullability_analysis_test.cc
+++ b/nullability_verification/pointer_nullability_analysis_test.cc
@@ -486,6 +486,27 @@
UnorderedElementsAre(Pair("safe", IsSafe()), Pair("unsafe-1", IsUnsafe()),
Pair("unsafe-2", IsUnsafe())));
+ std::string DerefStructMemberInsideMemberFunction = R"(
+ struct Foo {
+ Foo* ptr;
+ void target() {
+ if (ptr) {
+ *ptr;
+ /*[[safe]]*/
+ } else {
+ *ptr;
+ /*[[unsafe-1]]*/
+ }
+ *ptr;
+ /*[[unsafe-2]]*/
+ }
+ };
+ )";
+ expectDataflow(
+ DerefStructMemberInsideMemberFunction,
+ UnorderedElementsAre(Pair("safe", IsSafe()), Pair("unsafe-1", IsUnsafe()),
+ Pair("unsafe-2", IsUnsafe())));
+
std::string DerefClassMember = R"(
class Foo {
public:
@@ -531,6 +552,43 @@
UnorderedElementsAre(Pair("safe", IsSafe()), Pair("unsafe-1", IsUnsafe()),
Pair("unsafe-2", IsUnsafe())));
+ std::string MemberAccessOnImplicitThis = R"(
+ struct Foo {
+ void foo();
+ void target() {
+ foo();
+ /*[[safe]]*/
+ }
+ };
+ )";
+ expectDataflow(MemberAccessOnImplicitThis,
+ UnorderedElementsAre(Pair("safe", IsSafe())));
+
+ std::string MemberAccessOnExplicitThis = R"(
+ struct Foo {
+ void foo();
+ void target() {
+ this->foo();
+ /*[[safe]]*/
+ }
+ };
+ )";
+ expectDataflow(MemberAccessOnExplicitThis,
+ UnorderedElementsAre(Pair("safe", IsSafe())));
+
+ std::string MemberAccessOnCopyOfThis = R"(
+ struct Foo {
+ void foo();
+ void target() {
+ Foo *thisCopy = this;
+ thisCopy->foo();
+ /*[[safe]]*/
+ }
+ };
+ )";
+ expectDataflow(MemberAccessOnCopyOfThis,
+ UnorderedElementsAre(Pair("safe", IsSafe())));
+
std::string AccessChainOnlyCheckOnFirst = R"(
struct Foo {
Foo* foo;
diff --git a/nullability_verification/pointer_nullability_matchers.cc b/nullability_verification/pointer_nullability_matchers.cc
index c37ce4a..e3b235e 100644
--- a/nullability_verification/pointer_nullability_matchers.cc
+++ b/nullability_verification/pointer_nullability_matchers.cc
@@ -13,6 +13,7 @@
using ast_matchers::anyOf;
using ast_matchers::binaryOperator;
+using ast_matchers::cxxThisExpr;
using ast_matchers::declRefExpr;
using ast_matchers::expr;
using ast_matchers::hasAnyOperatorName;
@@ -51,6 +52,7 @@
Matcher<Stmt> isMemberExprInvolvingPointers() {
return memberExpr(anyOf(isArrow(), hasType(isAnyPointer())));
}
+Matcher<Stmt> isCXXThisExpr() { return cxxThisExpr(); }
} // namespace nullability
} // namespace tidy
} // namespace clang
diff --git a/nullability_verification/pointer_nullability_matchers.h b/nullability_verification/pointer_nullability_matchers.h
index b4f4a78..23b42b8 100644
--- a/nullability_verification/pointer_nullability_matchers.h
+++ b/nullability_verification/pointer_nullability_matchers.h
@@ -13,6 +13,7 @@
ast_matchers::internal::Matcher<Stmt> isPointerVariableReference();
ast_matchers::internal::Matcher<Stmt> isMemberExprInvolvingPointers();
+ast_matchers::internal::Matcher<Stmt> isCXXThisExpr();
ast_matchers::internal::Matcher<Stmt> isNullPointerLiteral();
ast_matchers::internal::Matcher<Stmt> isAddrOf();
ast_matchers::internal::Matcher<Stmt> isPointerDereference();