Add transfer function for `UnaryOperator`, particularly addr/deref.
PiperOrigin-RevId: 502831558
diff --git a/nullability_verification/pointer_nullability_analysis.cc b/nullability_verification/pointer_nullability_analysis.cc
index df80954..d24073a 100644
--- a/nullability_verification/pointer_nullability_analysis.cc
+++ b/nullability_verification/pointer_nullability_analysis.cc
@@ -162,6 +162,18 @@
clang::ASTDumper(OS, /*ShowColors=*/false).Visit(Node);
}
+std::vector<NullabilityKind> unspecifiedNullability(const Expr* E) {
+ return std::vector<NullabilityKind>(countPointersInType(E),
+ NullabilityKind::Unspecified);
+}
+
+std::vector<NullabilityKind> prepend(NullabilityKind Head,
+ ArrayRef<NullabilityKind> Tail) {
+ std::vector<NullabilityKind> Result = {Head};
+ Result.insert(Result.end(), Tail.begin(), Tail.end());
+ return Result;
+}
+
// Returns the computed nullability for a subexpr of the current expression.
// This is always available as we compute bottom-up.
ArrayRef<NullabilityKind> getNullabilityForChild(
@@ -175,11 +187,12 @@
dump(E, llvm::dbgs());
llvm::dbgs() << "==================================\n";
- return std::vector<NullabilityKind>(countPointersInType(E),
- NullabilityKind::Unspecified);
+ return unspecifiedNullability(E);
});
}
+// TODO: Much logic is the same as GetNullabilityAnnotationsFromTypeVisitor.
+// Find a way to unify the two.
class SubstituteNullabilityAnnotationsInTemplateVisitor
: public TypeVisitor<SubstituteNullabilityAnnotationsInTemplateVisitor> {
std::vector<NullabilityKind> NullabilityAnnotations;
@@ -227,6 +240,26 @@
}
}
}
+
+ void VisitAttributedType(const AttributedType* AT) {
+ Optional<NullabilityKind> NK = AT->getImmediateNullability();
+ if (NK.has_value()) {
+ NullabilityAnnotations.push_back(*NK);
+ QualType MT = AT->getModifiedType();
+ if (auto PT = MT->getAs<PointerType>()) {
+ Visit(PT->getPointeeType());
+ } else {
+ // TODO: Handle this unusual yet possible (e.g. through typedefs)
+ // case.
+ llvm::dbgs() << "\nThe type " << AT
+ << "contains a nullability annotation that is not "
+ << "succeeded by a pointer type. "
+ << "This occurence is not currently handled.\n";
+ }
+ } else {
+ Visit(AT->getModifiedType());
+ }
+ }
};
/// Compute the nullability annotation of type `T`, which contains types
@@ -549,6 +582,45 @@
});
}
+void transferNonFlowSensitiveUnaryOperator(
+ const UnaryOperator* UO, const MatchFinder::MatchResult& MR,
+ TransferState<PointerNullabilityLattice>& State) {
+ (void)State.Lattice.insertExprNullabilityIfAbsent(
+ UO, [&]() -> std::vector<NullabilityKind> {
+ switch (UO->getOpcode()) {
+ case UO_AddrOf:
+ return prepend(NullabilityKind::NonNull,
+ getNullabilityForChild(UO->getSubExpr(), State));
+ case UO_Deref:
+ if (auto Base = getNullabilityForChild(UO->getSubExpr(), State);
+ !Base.empty()) {
+ return Base.drop_front(1).vec();
+ } else {
+ // TODO: this can only happen if the child nullability has the
+ // wrong length, remove once the invariant is enforced.
+ return unspecifiedNullability(UO);
+ }
+
+ case UO_PostInc:
+ case UO_PostDec:
+ case UO_PreInc:
+ case UO_PreDec:
+ case UO_Plus:
+ case UO_Minus:
+ case UO_Not:
+ case UO_LNot:
+ case UO_Real:
+ case UO_Imag:
+ case UO_Extension:
+ return getNullabilityForChild(UO->getSubExpr(), State);
+
+ case UO_Coawait:
+ // TODO: work out what to do here!
+ return unspecifiedNullability(UO);
+ }
+ });
+}
+
auto buildNonFlowSensitiveTransferer() {
return CFGMatchSwitchBuilder<TransferState<PointerNullabilityLattice>>()
.CaseOfCFGStmt<DeclRefExpr>(ast_matchers::declRefExpr(),
@@ -564,6 +636,8 @@
transferNonFlowSensitiveMaterializeTemporaryExpr)
.CaseOfCFGStmt<CallExpr>(ast_matchers::callExpr(),
transferNonFlowSensitiveCallExpr)
+ .CaseOfCFGStmt<UnaryOperator>(ast_matchers::unaryOperator(),
+ transferNonFlowSensitiveUnaryOperator)
.Build();
}