[nullability] Emit a warning on array subscripts if the base is nullable.
I noticed that this was missing while preparing to add the corresponding
functionality for smart pointers.
PiperOrigin-RevId: 590861070
Change-Id: I3e16ce8107392c9632e0ab9d43fead1ed32d93d8
diff --git a/nullability/pointer_nullability_diagnosis.cc b/nullability/pointer_nullability_diagnosis.cc
index 85ea4b9..e9c39eb 100644
--- a/nullability/pointer_nullability_diagnosis.cc
+++ b/nullability/pointer_nullability_diagnosis.cc
@@ -87,6 +87,15 @@
PointerNullabilityDiagnostic::Context::NullableDereference);
}
+SmallVector<PointerNullabilityDiagnostic> diagnoseSubscript(
+ absl::Nonnull<const ArraySubscriptExpr *> Subscript,
+ const MatchFinder::MatchResult &,
+ const TransferStateForDiagnostics<PointerNullabilityLattice> &State) {
+ return diagnoseNonnullExpected(
+ Subscript->getBase(), State.Env,
+ PointerNullabilityDiagnostic::Context::NullableDereference);
+}
+
SmallVector<PointerNullabilityDiagnostic> diagnoseArrow(
absl::Nonnull<const MemberExpr *> MemberExpr,
const MatchFinder::MatchResult &Result,
@@ -329,6 +338,9 @@
SmallVector<PointerNullabilityDiagnostic>>()
// (*)
.CaseOfCFGStmt<UnaryOperator>(isPointerDereference(), diagnoseDereference)
+ // ([])
+ .CaseOfCFGStmt<ArraySubscriptExpr>(isPointerSubscript(),
+ diagnoseSubscript)
// (->)
.CaseOfCFGStmt<MemberExpr>(isPointerArrow(), diagnoseArrow)
// Check compatibility of parameter assignments
diff --git a/nullability/pointer_nullability_matchers.cc b/nullability/pointer_nullability_matchers.cc
index d5e9781..29c858e 100644
--- a/nullability/pointer_nullability_matchers.cc
+++ b/nullability/pointer_nullability_matchers.cc
@@ -15,6 +15,7 @@
using ast_matchers::anyOf;
using ast_matchers::argumentCountIs;
+using ast_matchers::arraySubscriptExpr;
using ast_matchers::binaryOperator;
using ast_matchers::booleanType;
using ast_matchers::callee;
@@ -36,6 +37,7 @@
using ast_matchers::hasAnyOperatorName;
using ast_matchers::hasAnyOverloadedOperatorName;
using ast_matchers::hasArgument;
+using ast_matchers::hasBase;
using ast_matchers::hasBody;
using ast_matchers::hasCanonicalType;
using ast_matchers::hasCastKind;
@@ -77,6 +79,9 @@
Matcher<Stmt> isPointerDereference() {
return unaryOperator(hasOperatorName("*"), hasUnaryOperand(isPointerExpr()));
}
+Matcher<Stmt> isPointerSubscript() {
+ return arraySubscriptExpr(hasBase(isPointerExpr()));
+}
Matcher<Stmt> isPointerCheckBinOp() {
return binaryOperator(hasAnyOperatorName("!=", "=="),
hasOperands(isPointerExpr(), isPointerExpr()));
diff --git a/nullability/pointer_nullability_matchers.h b/nullability/pointer_nullability_matchers.h
index 68f2dfe..0ce2059 100644
--- a/nullability/pointer_nullability_matchers.h
+++ b/nullability/pointer_nullability_matchers.h
@@ -37,6 +37,7 @@
ast_matchers::internal::Matcher<Stmt> isNullPointerLiteral();
ast_matchers::internal::Matcher<Stmt> isAddrOf();
ast_matchers::internal::Matcher<Stmt> isPointerDereference();
+ast_matchers::internal::Matcher<Stmt> isPointerSubscript();
ast_matchers::internal::Matcher<Stmt> isPointerCheckBinOp();
ast_matchers::internal::Matcher<Stmt> isImplicitCastPointerToBool();
ast_matchers::internal::Matcher<Stmt> isCallExpr();
diff --git a/nullability/test/basic.cc b/nullability/test/basic.cc
index 1373420..8f6eae6 100644
--- a/nullability/test/basic.cc
+++ b/nullability/test/basic.cc
@@ -233,5 +233,19 @@
)cc"));
}
+TEST(PointerNullabilityTest, ArraySubscript) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void target(int *_Nonnull nonnull, int *_Nullable nullable, int *unknown) {
+ nonnull[0];
+ nullable[0]; // [[unsafe]]
+ unknown[0];
+
+ 0 [nonnull];
+ 0 [nullable]; // [[unsafe]]
+ 0 [unknown];
+ }
+ )cc"));
+}
+
} // namespace
} // namespace clang::tidy::nullability