summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorGeorge Karpenkov <ekarpenkov@apple.com>2018-05-31 00:28:13 +0000
committerGeorge Karpenkov <ekarpenkov@apple.com>2018-05-31 00:28:13 +0000
commit7744c7f137bc7c079353f0ca40b7fa2b26bcdb3b (patch)
tree95d994482f7753ee7d043fe66e0f2de6e909cfb5 /clang/lib
parente5bc4417913a3e606d572a5d661106612d3a99a7 (diff)
downloadbcm5719-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.cpp48
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);
OpenPOWER on IntegriCloud