patch to issue warning on comparing parameters with
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 23 Oct 2014 19:00:10 +0000 (19:00 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 23 Oct 2014 19:00:10 +0000 (19:00 +0000)
nonnull attribute when comparison is always
true/false. Patch by Steven Wu with few fixes and minor
refactoring and adding tests by me. rdar://18712242

llvm-svn: 220496

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaChecking.cpp
clang/test/Sema/nonnull.c

index e6ad4b5..8197f7d 100644 (file)
@@ -2500,6 +2500,10 @@ def warn_impcast_pointer_to_bool : Warning<
     "address of%select{| function| array}0 '%1' will always evaluate to "
     "'true'">,
     InGroup<PointerBoolConversion>;
+def warn_cast_nonnull_to_bool : Warning<
+    "nonnull parameter '%0' will always evaluate to "
+    "'true'">,
+    InGroup<PointerBoolConversion>;
 def warn_this_bool_conversion : Warning<
   "'this' pointer cannot be null in well-defined C++ code; pointer may be "
   "assumed to always convert to true">, InGroup<UndefinedBoolConversion>;
@@ -2512,6 +2516,10 @@ def warn_null_pointer_compare : Warning<
     "comparison of %select{address of|function|array}0 '%1' %select{not |}2"
     "equal to a null pointer is always %select{true|false}2">,
     InGroup<TautologicalPointerCompare>;
+def warn_nonnull_parameter_compare : Warning<
+    "comparison of nonnull parameter '%0' %select{not |}1"
+    "equal to a null pointer is always %select{true|false}1">,
+    InGroup<TautologicalPointerCompare>;
 def warn_this_null_compare : Warning<
   "'this' pointer cannot be null in well-defined C++ code; comparison may be "
   "assumed to always evaluate to %select{true|false}0">,
index fd2fa0c..495fa32 100644 (file)
@@ -6678,7 +6678,37 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
   // Weak Decls can be null.
   if (!D || D->isWeak())
     return;
-
+  // Check for parameter decl with nonnull attribute
+  if (ParmVarDecl* PV = dyn_cast<ParmVarDecl>(D)) {
+    if (FunctionDecl* FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+      unsigned NumArgs = FD->getNumParams();
+      llvm::SmallBitVector AttrNonNull(NumArgs);
+      for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
+        if (!NonNull->args_size()) {
+          AttrNonNull.set(0, NumArgs);
+          break;
+        }
+        for (unsigned Val : NonNull->args()) {
+          if (Val >= NumArgs)
+            continue;
+          AttrNonNull.set(Val);
+        }
+      }
+      if (!AttrNonNull.empty())
+        for (unsigned i = 0; i < NumArgs; ++i)
+          if (FD->getParamDecl(i) == PV && AttrNonNull[i]) {
+            std::string Str;
+            llvm::raw_string_ostream S(Str);
+            E->printPretty(S, nullptr, getPrintingPolicy());
+            unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare
+                                        : diag::warn_cast_nonnull_to_bool;
+            Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange()
+              << Range << IsEqual;
+            return;
+          }
+    }
+  }
+  
   QualType T = D->getType();
   const bool IsArray = T->isArrayType();
   const bool IsFunction = T->isFunctionType();
index 3b654a8..53f94dd 100644 (file)
@@ -83,3 +83,28 @@ void redecl_test(void *p) {
   redecl(p, 0); // expected-warning{{null passed}}
   redecl(0, p); // expected-warning{{null passed}}
 }
+
+// rdar://18712242
+#define NULL (void*)0
+__attribute__((__nonnull__))
+int evil_nonnull_func(int* pointer, void * pv)
+{
+   if (pointer == NULL) {  // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}}
+     return 0;
+   } else {
+     return *pointer;
+   } 
+
+   if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}}
+}
+
+int another_evil_nonnull_func(int* pointer, char ch, void * pv) __attribute__((nonnull(1, 3)));
+int another_evil_nonnull_func(int* pointer, char ch, void * pv) {
+   if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is always false}}
+     return 0;
+   } else {
+     return *pointer;
+   } 
+
+   if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is always false}}
+}