]> granicus.if.org Git - clang/commitdiff
[analyzer] Nullability: add option to not report on calls to system headers.
authorDevin Coughlin <dcoughlin@apple.com>
Sat, 5 Mar 2016 01:32:43 +0000 (01:32 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Sat, 5 Mar 2016 01:32:43 +0000 (01:32 +0000)
Add an -analyzer-config 'nullability:NoDiagnoseCallsToSystemHeaders' option to
the nullability checker. When enabled, this option causes the analyzer to not
report about passing null/nullable values to functions and methods declared
in system headers.

This option is motivated by the observation that large projects may have many
nullability warnings. These projects may find warnings about nullability
annotations that they have explicitly added themselves higher priority to fix
than warnings on calls to system libraries.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@262763 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
test/Analysis/Inputs/system-header-simulator-for-nullability.h [new file with mode: 0644]
test/Analysis/nullability.mm
test/Analysis/nullability_nullonly.mm

index e096e2047f5ebae2b5be5d3a44a863bdbb06ad0a..31560f2687c678522e47abf3cd74acd44f07308e 100644 (file)
@@ -100,6 +100,14 @@ class NullabilityChecker
   mutable std::unique_ptr<BugType> BT;
 
 public:
+  // If true, the checker will not diagnose nullabilility issues for calls
+  // to system headers. This option is motivated by the observation that large
+  // projects may have many nullability warnings. These projects may
+  // find warnings about nullability annotations that they have explicitly
+  // added themselves higher priority to fix than warnings on calls to system
+  // libraries.
+  DefaultBool NoDiagnoseCallsToSystemHeaders;
+
   void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
   void checkPostStmt(const ExplicitCastExpr *CE, CheckerContext &C) const;
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@@ -191,6 +199,15 @@ private:
   /// to the wrapped region. Otherwise it will return a nullptr.
   const SymbolicRegion *getTrackRegion(SVal Val,
                                        bool CheckSuperRegion = false) const;
+
+  /// Returns true if the call is diagnosable in the currrent analyzer
+  /// configuration.
+  bool isDiagnosableCall(const CallEvent &Call) const {
+    if (NoDiagnoseCallsToSystemHeaders && Call.isInSystemHeader())
+      return false;
+
+    return true;
+  }
 };
 
 class NullabilityState {
@@ -620,7 +637,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
 
     if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
         ArgExprTypeLevelNullability != Nullability::Nonnull &&
-        RequiredNullability == Nullability::Nonnull) {
+        RequiredNullability == Nullability::Nonnull &&
+        isDiagnosableCall(Call)) {
       ExplodedNode *N = C.generateErrorNode(State);
       if (!N)
         return;
@@ -647,7 +665,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
         continue;
 
       if (Filter.CheckNullablePassedToNonnull &&
-          RequiredNullability == Nullability::Nonnull) {
+          RequiredNullability == Nullability::Nonnull &&
+          isDiagnosableCall(Call)) {
         ExplodedNode *N = C.addTransition(State);
         SmallString<256> SBuf;
         llvm::raw_svector_ostream OS(SBuf);
@@ -1106,6 +1125,10 @@ void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,
     checker->Filter.Check##name = true;                                        \
     checker->Filter.CheckName##name = mgr.getCurrentCheckName();               \
     checker->NeedTracking = checker->NeedTracking || trackingRequired;         \
+    checker->NoDiagnoseCallsToSystemHeaders =                                  \
+        checker->NoDiagnoseCallsToSystemHeaders ||                             \
+        mgr.getAnalyzerOptions().getBooleanOption(                             \
+                      "NoDiagnoseCallsToSystemHeaders", false, checker, true); \
   }
 
 // The checks are likely to be turned on by default and it is possible to do
diff --git a/test/Analysis/Inputs/system-header-simulator-for-nullability.h b/test/Analysis/Inputs/system-header-simulator-for-nullability.h
new file mode 100644 (file)
index 0000000..9bb2786
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma clang system_header
+
+#define nil 0
+#define BOOL int
+
+#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+#define NS_ASSUME_NONNULL_END   _Pragma("clang assume_nonnull end")
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef struct _NSZone NSZone;
+
+@protocol NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@protocol NSCopying
+- (id)copyWithZone:(nullable NSZone *)zone;
+@end
+
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(nullable NSZone *)zone;
+@end
+
+__attribute__((objc_root_class))
+@interface
+NSObject<NSObject>
+@end
+
+@interface NSString : NSObject<NSCopying>
+- (BOOL)isEqualToString : (NSString *)aString;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+@end
+
+void NSSystemFunctionTakingNonnull(NSString *s);
+
+@interface NSSystemClass : NSObject
+- (void) takesNonnull:(NSString *)s;
+@end
+
+NS_ASSUME_NONNULL_END
index 220a38118aa2f1fa5f90c185f378d134d5c40ded..0a3ae7a1968c6fedc83aea25f32b1a042d35fd07 100644 (file)
@@ -1,38 +1,7 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -DNOSYSTEMHEADERS=0 -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
 
-#define nil 0
-#define BOOL int
-
-#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
-#define NS_ASSUME_NONNULL_END   _Pragma("clang assume_nonnull end")
-
-typedef struct _NSZone NSZone;
-
-@protocol NSObject
-+ (id)alloc;
-- (id)init;
-@end
-
-NS_ASSUME_NONNULL_BEGIN
-@protocol NSCopying
-- (id)copyWithZone:(nullable NSZone *)zone;
-
-@end
-
-@protocol NSMutableCopying
-- (id)mutableCopyWithZone:(nullable NSZone *)zone;
-@end
-NS_ASSUME_NONNULL_END
-
-__attribute__((objc_root_class))
-@interface
-NSObject<NSObject>
-@end
-
-@interface NSString : NSObject<NSCopying>
-- (BOOL)isEqualToString : (NSString *_Nonnull)aString;
-- (NSString *)stringByAppendingString:(NSString *_Nonnull)aString;
-@end
+#include "Inputs/system-header-simulator-for-nullability.h"
 
 @interface TestObject : NSObject
 - (int *_Nonnull)returnsNonnull;
@@ -419,3 +388,24 @@ Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
   return newInstance;
 }
 @end
+
+NSString * _Nullable returnsNullableString();
+
+void callFunctionInSystemHeader() {
+  NSString *s = returnsNullableString();
+
+  NSSystemFunctionTakingNonnull(s);
+  #if !NOSYSTEMHEADERS
+  // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+  #endif
+}
+
+void callMethodInSystemHeader() {
+  NSString *s = returnsNullableString();
+
+  NSSystemClass *sc = [[NSSystemClass alloc] init];
+  [sc takesNonnull:s];
+  #if !NOSYSTEMHEADERS
+  // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+  #endif
+}
index d82105cf5b55b723867b3fad81fe1c5af6ea5f34..9671877719f36d251a4d730f526547e6d4fb7dc3 100644 (file)
@@ -1,20 +1,7 @@
-// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
+// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -DNOSYSTEMHEADERS=0 -verify %s
+// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
 
-#define nil 0
-#define BOOL int
-
-@protocol NSObject
-+ (id)alloc;
-- (id)init;
-@end
-
-@protocol NSCopying
-@end
-
-__attribute__((objc_root_class))
-@interface
-NSObject<NSObject>
-@end
+#include "Inputs/system-header-simulator-for-nullability.h"
 
 int getRandom();
 
@@ -159,3 +146,25 @@ TestObject * _Nonnull returnsNilObjCInstanceDirectlyWithSuppressingCast() {
     return p; // no-warning
 }
 @end
+
+
+void callFunctionInSystemHeader() {
+  NSString *s;
+  s = nil;
+
+  NSSystemFunctionTakingNonnull(s);
+  #if !NOSYSTEMHEADERS
+  // expected-warning@-2{{Null passed to a callee that requires a non-null 1st parameter}}
+  #endif
+}
+
+void callMethodInSystemHeader() {
+  NSString *s;
+  s = nil;
+
+  NSSystemClass *sc = [[NSSystemClass alloc] init];
+  [sc takesNonnull:s];
+  #if !NOSYSTEMHEADERS
+  // expected-warning@-2{{Null passed to a callee that requires a non-null 1st parameter}}
+  #endif
+}