Re: [PATCH] D22968: [analyzer] A checker for macOS-specific bool-like objects.

2016-09-23 Thread Anna Zaks via cfe-commits
zaks.anna added a comment.

Here are more comments. Could you address/answer these and upload the latest 
patch that compares NSNumber to other numbers?

Thanks!



Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:88
@@ +87,3 @@
+
+auto NSNumberExprM =
+expr(ignoringParenImpCasts(expr(hasType(hasCanonicalType(

Can you test if matching for NSNumber works when they come from ivars, 
properties, and method returns,  works?



Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:117
@@ +116,3 @@
+auto ConversionThroughComparisonM =
+binaryOperator(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+   hasEitherOperand(NSNumberExprM),

Can we use any binary operator here without any restrictions?


Comment at: test/Analysis/bool-conversion.cpp:18
@@ +17,3 @@
+#ifdef PEDANTIC
+  if (p) {} // expected-warning{{}}
+  if (!p) {} // expected-warning{{}}

dcoughlin wrote:
> It is generally good to include the diagnostic text in the test for the 
> warning. This way we make sure we get the warning we expected.
+1

Are these pedantic because we assume these are comparing the pointer and not 
the value? Have you checked that this is a common idiom?

Same comment applies to NSNumber. If it is common practice to compare against 
nil..



Comment at: test/Analysis/bool-conversion.cpp:21
@@ +20,3 @@
+  p ? 1 : 2; // expected-warning{{}}
+  (bool)p; // expected-warning{{}}
+#endif

Why is this OK?


Comment at: test/Analysis/bool-conversion.m:2
@@ +1,3 @@
+// RUN: %clang_cc1 -fblocks -w -analyze 
-analyzer-checker=alpha.osx.BoolConversion %s -verify
+// RUN: %clang_cc1 -fblocks -w -analyze 
-analyzer-checker=alpha.osx.BoolConversion -analyzer-config 
alpha.osx.BoolConversion:Pedantic=true -DPEDANTIC %s -verify
+

dcoughlin wrote:
> You should add a test invocation here where -fobjc-arc is set as well. This 
> adds a bunch of implicit goop that it would be good to test with.
+ 1!!!
Especially, since we are matching the AST.


Comment at: test/Analysis/bool-conversion.m:10
@@ +9,3 @@
+  if (!p) {} // expected-warning{{}}
+  if (p == YES) {} // expected-warning{{}}
+  if (p == NO) {} // expected-warning{{}}

dcoughlin wrote:
> There is a Sema warning for `p == YES` already, right? ("comparison between 
> pointer and integer ('NSNumber *' and 'int')")
These tests seem to be even more relevant to OSBoolean.


https://reviews.llvm.org/D22968



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22968: [analyzer] A checker for macOS-specific bool-like objects.

2016-09-12 Thread Anna Zaks via cfe-commits
zaks.anna added a comment.

Let's test it on more real word bugs.



Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:11
@@ +10,3 @@
+// This file defines BoolConversionChecker, which checks for a particular
+// common mistake when dealing with NSNumber and OSBoolean objects:
+// When having a pointer P to such object, neither `if (P)' nor `bool X = P'

Should we warn on comparisons of NSNumber to '0'? Comparisons to 'nil' would be 
considered a proper pointer comparison, while comparisons to literal '0' would 
be considered a faulty comparison of the numbers.


Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:49
@@ +48,3 @@
+  virtual void run(const MatchFinder::MatchResult &Result) {
+// This callback only throws reports. All the logic is in the matchers.
+const Stmt *Conv = Result.Nodes.getNodeAs("conv");

"throws" -> "generates"?


https://reviews.llvm.org/D22968



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22968: [analyzer] A checker for macOS-specific bool-like objects.

2016-08-26 Thread Devin Coughlin via cfe-commits
dcoughlin added inline comments.


Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:62
@@ +61,3 @@
+   << "' to a plain boolean value: probably a forgotten "
+   << (IsObjC ? "'[boolValue]'" : "'->isTrue()'");
+BR.EmitBasicReport(

- The '[boolValue]' thing here is weird. Maybe use '-boolValue' instead?
- How about "Comparison between 'NSNumber *' and 'BOOL'; use -boolValue 
instead."
- You probably want to remove lifetime qualifiers from the type with 
`.getUnqualifiedType()`. before printing (i.e., don't mention '__strong') in 
the diagnostic.



Comment at: lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp:80
@@ +79,3 @@
+
+auto OSBooleanExprM =
+expr(ignoringParenImpCasts(

The AST matchers seem pretty convenient!


Comment at: test/Analysis/bool-conversion.cpp:18
@@ +17,3 @@
+#ifdef PEDANTIC
+  if (p) {} // expected-warning{{}}
+  if (!p) {} // expected-warning{{}}

It is generally good to include the diagnostic text in the test for the 
warning. This way we make sure we get the warning we expected.


Comment at: test/Analysis/bool-conversion.m:2
@@ +1,3 @@
+// RUN: %clang_cc1 -fblocks -w -analyze 
-analyzer-checker=alpha.osx.BoolConversion %s -verify
+// RUN: %clang_cc1 -fblocks -w -analyze 
-analyzer-checker=alpha.osx.BoolConversion -analyzer-config 
alpha.osx.BoolConversion:Pedantic=true -DPEDANTIC %s -verify
+

You should add a test invocation here where -fobjc-arc is set as well. This 
adds a bunch of implicit goop that it would be good to test with.


Comment at: test/Analysis/bool-conversion.m:6
@@ +5,3 @@
+
+void bad(const NSNumber *p) {
+#ifdef PEDANTIC

These 'const's are not idiomatic. It is probably better to remove them.


Comment at: test/Analysis/bool-conversion.m:10
@@ +9,3 @@
+  if (!p) {} // expected-warning{{}}
+  if (p == YES) {} // expected-warning{{}}
+  if (p == NO) {} // expected-warning{{}}

There is a Sema warning for `p == YES` already, right? ("comparison between 
pointer and integer ('NSNumber *' and 'int')")


Comment at: test/Analysis/bool-conversion.m:11
@@ +10,3 @@
+  if (p == YES) {} // expected-warning{{}}
+  if (p == NO) {} // expected-warning{{}}
+  (!p) ? 1 : 2; // expected-warning{{}}

Should `p == NO` be on in non-pedantic mode, as well? It also seems to me that 
you could warn on comparison of *any* ObjCObjectPointerType type to `NO`. At a 
minimum it would probably be good to check for comparisons of `id` to NO.


https://reviews.llvm.org/D22968



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D22968: [analyzer] A checker for macOS-specific bool-like objects.

2016-07-29 Thread Artem Dergachev via cfe-commits
NoQ created this revision.
NoQ added reviewers: zaks.anna, dcoughlin.
NoQ added a subscriber: cfe-commits.

If you store a boolean value as an Objective-C object `NSNumber *X`, and want 
to see if it's true or false, than it's not a good idea to write this check as 
'X == YES'. Because X is a pointer, and it is unlikely that it's equal to 1. 
You perhaps wanted to say `[X boolValue]` instead.

Similarly, in XNU/driver code, if you have a C++ object `OSBoolean *X`, which 
points to one of the two immutable objects - `kOSBooleanTrue` or 
`kOSBooleanFalse` , it's not a good idea to convert `X` to a C++ bool directly 
(eg. `bool B = X`). You want to compare it to `kOSBooleanTrue` or call the 
`->isTrue()` method instead.

Bugs of both kinds have been noticed in real-world code, so i'm attempting to 
make a simple checker for that. It is purely AST-based and moreover uses only 
ASTMatchers for everything (which makes it the first analyzer checker to use 
AST matchers). In fact i'm not sure if this checker should be in the analyzer 
or in clang-tidy; there should be no problem to move it around.

I'm still going to tweak these matchers a bit, as i'm in the middle of 
gathering statistics.

https://reviews.llvm.org/D22968

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/BoolConversionChecker.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  test/Analysis/Inputs/system-header-simulator-objc.h
  test/Analysis/bool-conversion.cpp
  test/Analysis/bool-conversion.m

Index: test/Analysis/bool-conversion.m
===
--- /dev/null
+++ test/Analysis/bool-conversion.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fblocks -w -analyze -analyzer-checker=alpha.osx.BoolConversion %s -verify
+// RUN: %clang_cc1 -fblocks -w -analyze -analyzer-checker=alpha.osx.BoolConversion -analyzer-config alpha.osx.BoolConversion:Pedantic=true -DPEDANTIC %s -verify
+
+#include "Inputs/system-header-simulator-objc.h"
+
+void bad(const NSNumber *p) {
+#ifdef PEDANTIC
+  if (p) {} // expected-warning{{}}
+  if (!p) {} // expected-warning{{}}
+  if (p == YES) {} // expected-warning{{}}
+  if (p == NO) {} // expected-warning{{}}
+  (!p) ? 1 : 2; // expected-warning{{}}
+  (BOOL)p; // expected-warning{{}}
+#endif
+  BOOL x = p; // expected-warning{{}}
+  x = p; // expected-warning{{}}
+  x = (p == YES); // expected-warning{{}}
+}
+
+typedef const NSNumber *SugaredNumber;
+void bad_sugared(SugaredNumber p) {
+  p == YES; // expected-warning{{}}
+}
+
+void good(const NSNumber *p) {
+  if ([p boolValue] == NO) {} // no-warning
+  if ([p boolValue] == YES) {} // no-warning
+  BOOL x = [p boolValue]; // no-warning
+}
+
+void suppression(const NSNumber *p) {
+  if (p == NULL) {} // no-warning
+  if (p == nil) {} // no-warning
+}
Index: test/Analysis/bool-conversion.cpp
===
--- /dev/null
+++ test/Analysis/bool-conversion.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -w -std=c++11 -analyze -analyzer-checker=alpha.osx.BoolConversion %s -verify
+// RUN: %clang_cc1 -w -std=c++11 -analyze -analyzer-checker=alpha.osx.BoolConversion -analyzer-config alpha.osx.BoolConversion:Pedantic=true -DPEDANTIC %s -verify
+
+#define NULL ((void *)0)
+#include "Inputs/system-header-simulator-cxx.h" // for nullptr
+
+class OSBoolean {
+public:
+  virtual bool isTrue() const;
+  virtual bool isFalse() const;
+};
+
+extern const OSBoolean *const &kOSBooleanFalse;
+extern const OSBoolean *const &kOSBooleanTrue;
+
+void bad(const OSBoolean *p) {
+#ifdef PEDANTIC
+  if (p) {} // expected-warning{{}}
+  if (!p) {} // expected-warning{{}}
+  p ? 1 : 2; // expected-warning{{}}
+  (bool)p; // expected-warning{{}}
+#endif
+  bool x = p; // expected-warning{{}}
+  x = p; // expected-warning{{}}
+}
+
+typedef bool sugared_bool;
+typedef const OSBoolean *sugared_OSBoolean;
+void bad_sugared(sugared_OSBoolean p) {
+  sugared_bool x = p; // expected-warning{{}}
+}
+
+void good(const OSBoolean *p) {
+  bool x = p->isTrue(); // no-warning
+  (bool)p->isFalse(); // no-warning
+  if (p == kOSBooleanTrue) {} // no-warning
+}
+
+void suppression(const OSBoolean *p) {
+  if (p == NULL) {} // no-warning
+  bool y = (p == nullptr); // no-warning
+}
Index: test/Analysis/Inputs/system-header-simulator-objc.h
===
--- test/Analysis/Inputs/system-header-simulator-objc.h
+++ test/Analysis/Inputs/system-header-simulator-objc.h
@@ -10,10 +10,16 @@
 
 typedef signed long CFIndex;
 typedef signed char BOOL;
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+
 typedef unsigned long NSUInteger;
 typedef unsigned short unichar;
 typedef UInt16 UniChar;
 
+#define NULL ((void *)0)
+#define nil ((id)0)
+
 enum {
 NSASCIIStringEncoding = 1,
 NSNEXTSTEPStringEncoding = 2,
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===
--- lib/StaticAn