r257938 - [analyzer] Check for return of nil in ObjC methods with nonnull return type.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 15 13:35:40 PST 2016


Author: dcoughlin
Date: Fri Jan 15 15:35:40 2016
New Revision: 257938

URL: http://llvm.org/viewvc/llvm-project?rev=257938&view=rev
Log:
[analyzer] Check for return of nil in ObjC methods with nonnull return type.

Update NullabilityChecker so that it checks return statements in ObjC methods.
Previously it was returning early because methods do not have a function type.

Also update detection of violated parameter _Nonnull preconditions to handle
ObjC methods.

rdar://problem/24200560

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
    cfe/trunk/test/Analysis/nullability_nullonly.mm

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp?rev=257938&r1=257937&r2=257938&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Fri Jan 15 15:35:40 2016
@@ -366,24 +366,20 @@ static bool checkPreconditionViolation(P
   if (!D)
     return false;
 
-  if (const auto *BlockD = dyn_cast<BlockDecl>(D)) {
-    if (checkParamsForPreconditionViolation(BlockD->parameters(), State,
-                                            LocCtxt)) {
-      if (!N->isSink())
-        C.addTransition(State->set<PreconditionViolated>(true), N);
-      return true;
-    }
+  ArrayRef<ParmVarDecl*> Params;
+  if (const auto *BD = dyn_cast<BlockDecl>(D))
+    Params = BD->parameters();
+  else if (const auto *FD = dyn_cast<FunctionDecl>(D))
+    Params = FD->parameters();
+  else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+    Params = MD->parameters();
+  else
     return false;
-  }
 
-  if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) {
-    if (checkParamsForPreconditionViolation(FuncDecl->parameters(), State,
-                                            LocCtxt)) {
-      if (!N->isSink())
-        C.addTransition(State->set<PreconditionViolated>(true), N);
-      return true;
-    }
-    return false;
+  if (checkParamsForPreconditionViolation(Params, State, LocCtxt)) {
+    if (!N->isSink())
+      C.addTransition(State->set<PreconditionViolated>(true), N);
+    return true;
   }
   return false;
 }
@@ -484,16 +480,20 @@ void NullabilityChecker::checkPreStmt(co
   if (!RetSVal)
     return;
 
+  QualType RequiredRetType;
   AnalysisDeclContext *DeclCtxt =
       C.getLocationContext()->getAnalysisDeclContext();
-  const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
-  if (!FuncType)
+  const Decl *D = DeclCtxt->getDecl();
+  if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
+    RequiredRetType = MD->getReturnType();
+  else if (auto *FD = dyn_cast<FunctionDecl>(D))
+    RequiredRetType = FD->getReturnType();
+  else
     return;
 
   NullConstraint Nullness = getNullConstraint(*RetSVal, State);
 
-  Nullability RequiredNullability =
-      getNullabilityAnnotation(FuncType->getReturnType());
+  Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
 
   // If the returned value is null but the type of the expression
   // generating it is nonnull then we will suppress the diagnostic.

Modified: cfe/trunk/test/Analysis/nullability_nullonly.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullability_nullonly.mm?rev=257938&r1=257937&r2=257938&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/nullability_nullonly.mm (original)
+++ cfe/trunk/test/Analysis/nullability_nullonly.mm Fri Jan 15 15:35:40 2016
@@ -1,5 +1,21 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
 
+#define nil 0
+#define BOOL int
+
+ at protocol NSObject
++ (id)alloc;
+- (id)init;
+ at end
+
+ at protocol NSCopying
+ at end
+
+__attribute__((objc_root_class))
+ at interface
+NSObject<NSObject>
+ at end
+
 int getRandom();
 
 typedef struct Dummy { int val; } Dummy;
@@ -85,3 +101,27 @@ Dummy *_Nonnull testDefensiveInlineCheck
     takesNonnull(p);
   return p;
 }
+
+
+ at interface SomeClass : NSObject
+ at end
+
+ at implementation SomeClass (MethodReturn)
+- (SomeClass * _Nonnull)testReturnsNilInNonnull {
+  SomeClass *local = nil;
+  return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+- (SomeClass * _Nonnull)testReturnsCastSuppressedNilInNonnull {
+  SomeClass *local = nil;
+  return (SomeClass * _Nonnull)local; // no-warning
+}
+
+- (SomeClass * _Nonnull)testReturnsNilInNonnullWhenPreconditionViolated:(SomeClass * _Nonnull) p {
+  SomeClass *local = nil;
+  if (!p) // Pre-condition violated here.
+    return local; // no-warning
+  else
+    return p; // no-warning
+}
+ at end




More information about the cfe-commits mailing list