diff options
author | George Karpenkov <ekarpenkov@apple.com> | 2018-05-31 00:28:13 +0000 |
---|---|---|
committer | George Karpenkov <ekarpenkov@apple.com> | 2018-05-31 00:28:13 +0000 |
commit | 7744c7f137bc7c079353f0ca40b7fa2b26bcdb3b (patch) | |
tree | 95d994482f7753ee7d043fe66e0f2de6e909cfb5 /clang/lib | |
parent | e5bc4417913a3e606d572a5d661106612d3a99a7 (diff) | |
download | bcm5719-llvm-7744c7f137bc7c079353f0ca40b7fa2b26bcdb3b.tar.gz bcm5719-llvm-7744c7f137bc7c079353f0ca40b7fa2b26bcdb3b.zip |
[analyzer] Trust _Nonnull annotations, and trust analyzer knowledge about receiver nullability
Previously, the checker was using the nullability of the expression,
which is nonnull IFF both receiver and method are annotated as _Nonnull.
However, the receiver could be known to the analyzer to be nonnull
without being explicitly marked as _Nonnull.
rdar://40635584
Differential Revision: https://reviews.llvm.org/D47510
llvm-svn: 333612
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp index 3b299441d1e..f3d68014224 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp @@ -25,18 +25,56 @@ using namespace ento; namespace { class TrustNonnullChecker : public Checker<check::PostCall> { +private: + /// \returns Whether we trust the result of the method call to be + /// a non-null pointer. + bool isNonNullPtr(const CallEvent &Call, CheckerContext &C) const { + QualType ExprRetType = Call.getResultType(); + if (!ExprRetType->isAnyPointerType()) + return false; + + if (getNullabilityAnnotation(ExprRetType) == Nullability::Nonnull) + return true; + + // The logic for ObjC instance method calls is more complicated, + // as the return value is nil when the receiver is nil. + if (!isa<ObjCMethodCall>(&Call)) + return false; + + const auto *MCall = cast<ObjCMethodCall>(&Call); + const ObjCMethodDecl *MD = MCall->getDecl(); + + // Distrust protocols. + if (isa<ObjCProtocolDecl>(MD->getDeclContext())) + return false; + + QualType DeclRetType = MD->getReturnType(); + if (getNullabilityAnnotation(DeclRetType) != Nullability::Nonnull) + return false; + + // For class messages it is sufficient for the declaration to be + // annotated _Nonnull. + if (!MCall->isInstanceMessage()) + return true; + + // Alternatively, the analyzer could know that the receiver is not null. + SVal Receiver = MCall->getReceiverSVal(); + ConditionTruthVal TV = C.getState()->isNonNull(Receiver); + if (TV.isConstrainedTrue()) + return true; + + return false; + } + public: void checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Only trust annotations for system headers for non-protocols. if (!Call.isInSystemHeader()) return; - QualType RetType = Call.getResultType(); - if (!RetType->isAnyPointerType()) - return; - ProgramStateRef State = C.getState(); - if (getNullabilityAnnotation(RetType) == Nullability::Nonnull) + + if (isNonNullPtr(Call, C)) if (auto L = Call.getReturnValue().getAs<Loc>()) State = State->assume(*L, /*Assumption=*/true); |