This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] NumberObjectConversion: Support OSNumber and CFNumberRef.
ClosedPublic

Authored by NoQ on Oct 18 2016, 8:34 AM.

Details

Summary

OSNumber and CFNumberRef, much like NSNumber*, can also be accidentally mistaken for a numeric value, so it is worth it to support this type in our new NumberObjectConversion checker.

Diff Detail

Repository
rL LLVM

Event Timeline

NoQ updated this revision to Diff 75011.Oct 18 2016, 8:34 AM
NoQ retitled this revision from to [analyzer] NumberObjectConversion: Support CFNumberRef..
NoQ updated this object.
NoQ added reviewers: zaks.anna, dcoughlin.
NoQ added a subscriber: cfe-commits.
zaks.anna added inline comments.Oct 18 2016, 12:04 PM
lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
72 ↗(On Diff #75011)

I'd keep the names more specific. By reading this code alone it looks like you are just checking for any ObjC object.

111 ↗(On Diff #75011)

Why do we need a case split here? Would calling getCanonicalType().getUnqualifiedType() result in a wrong result for ObjC?

129 ↗(On Diff #75011)

Let's just recommend nullptr for C++, but allow both NULL and nullptr.

152 ↗(On Diff #75011)

Please, use more a expressive name. I'd prefer a super long name if it's more expressive.

test/Analysis/number-object-conversion.c
14 ↗(On Diff #75011)

How about:
"Converting 'CFNumberRef' pointer to a plain boolean value; instead, compare the pointer to NULL or compare to the encapsulated scalar value"

  • I've added "pointer".
  • I would remove "for branching". Does it add anything?
  • Also, we should remove "please" as it makes the warning text longer.
NoQ retitled this revision from [analyzer] NumberObjectConversion: Support CFNumberRef. to [analyzer] NumberObjectConversion: Support OSNumber and CFNumberRef..Oct 20 2016, 11:27 AM
NoQ updated this object.

Ouch, i think i forgot about OSNumber, including tests.

lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
111 ↗(On Diff #75011)

It'd result in a wrong result for CFNumberRef, which is a typedef we shouldn't remove (turning this into struct __CFNumber * would be ugly).

I'd probably rather avoid the case split by removing the .getCanonicalType() part, because rarely anybody makes typedefs for NSNumber* or OSBoolean* etc (such as in tests with the word "sugared").

Or i could descend down to the necessary typedef for C objects, discarding all user's typedefs but not library typedefs. But that'd be even more complicated and probably not very useful for such minor matter.

alexander-shaposhnikov added inline comments.
lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
149 ↗(On Diff #75011)

probably it would make sense to move "MatchFinder F;" to the line 276 (closer to the place where it's actually being used)(or maybe i'm missing smth ?)

zaks.anna added inline comments.Oct 20 2016, 2:49 PM
lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
111 ↗(On Diff #75011)

It'd result in a wrong result for CFNumberRef, which is a typedef we shouldn't
remove (turning this into struct __CFNumber * would be ugly).

I see. Displaying "CFNumberRef" is definitely the right thing to do! Please, add a comment to explain this.

NoQ updated this revision to Diff 75411.Oct 21 2016, 4:31 AM
NoQ marked 5 inline comments as done.

Address review comments. Add the forgotten tests.

NoQ marked an inline comment as done.Oct 21 2016, 4:32 AM
NoQ added inline comments.
lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
149 ↗(On Diff #75011)

Yep, great idea.

test/Analysis/number-object-conversion.c
14 ↗(On Diff #75011)

I would remove "for branching". Does it add anything?

Because there's otherwise no obvious boolean value around, i wanted to point out what exactly is going on.

or compare to the encapsulated scalar value

They don't necessarily compare the value. Maybe "take"?

I've added "pointer".

Not sure it's worth keeping for other objects ("'NSNumber *' pointer" sounds like a pointer to a pointer).

zaks.anna added inline comments.Oct 21 2016, 10:03 AM
test/Analysis/number-object-conversion.c
23 ↗(On Diff #75411)

Comparing a pointer value of type '[CFNumberRef|NSNumber *]' to a primitive [boolean|integer] value; did you mean to compare the result of calling [API Name].

14 ↗(On Diff #75011)

or compare to the encapsulated scalar value

They don't necessarily compare the value. Maybe "take"?

OSBoolean or CFNumber:
[Comparing|Converting] a pointer value of type '[CFNumberRef|NSNumber *]' to a scalar [boolean|integer] value; instead, either compare the pointer to [NULL|nullptr|nil] or [call [APIName] | compare the result of calling [API Name]].

NSNumber or OSNumber:
Converting a pointer value of type '[NSNumber *]' to a scalar [boolean|integer] value; instead, either compare the pointer to [NULL|nullptr|nil] or call a method on '[NSNumber *]' to get the scalar value.

Comparing a pointer value of type '[NSNumber *]' to a scalar [boolean|integer] value; instead, either compare the pointer to [NULL|nullptr|nil] or call a method on '[NSNumber *]' to get the scalar value.

test/Analysis/number-object-conversion.cpp
32 ↗(On Diff #75411)

Converting a pointer value of type '[CFNumberRef|NSNumber *]' to a primitive [boolean|integer] value; did you mean to call [APIName].

41 ↗(On Diff #75411)

Same as cast.

NoQ updated this revision to Diff 75586.Oct 24 2016, 8:41 AM
NoQ marked an inline comment as done.
  • Update warning messages. I think it's better to pattern-match for integer sizes after all when we're suggesting API, this especially looks ugly for OSNumber (which is rare).
  • Add tests for converting CFNumberRef into intptr_t.
  • An unrelated change: Move casts to bools to non-pedantic mode (i mistakenly thought this check is loud).
NoQ marked 4 inline comments as done.Oct 24 2016, 8:43 AM
NoQ updated this revision to Diff 75612.Oct 24 2016, 10:32 AM

Do not suggest any API when we're not sure (was already advised by Anna but i missed it somehow).

zaks.anna accepted this revision.Oct 24 2016, 5:21 PM
zaks.anna edited edge metadata.

Minor nit below.

Thanks for iterating so much on this!
Anna.

test/Analysis/number-object-conversion.cpp
46 ↗(On Diff #75612)

Minor nit: Here, we want to use scalar instead of primitive so that both parts of the sentence are consistent. Devin did not like "scalar", but that's what it is called in the API docs, so I think should use that word in this specific case. (We can keep 'primitive' for the error messages that do not have "to get the ... value")

Sorry, this is a bit confusing.

This revision is now accepted and ready to land.Oct 24 2016, 5:21 PM
NoQ updated this revision to Diff 76043.EditedOct 27 2016, 8:48 AM
NoQ edited edge metadata.
  • Fix warning messages, finally, hopefully.
  • Make handling of macros much more careful, because errors of form x == Y, where X is an NSNumber pointer, and Y is a custom macro that expands to 0, were found.
dcoughlin accepted this revision.Oct 27 2016, 1:57 PM
dcoughlin edited edge metadata.

LGTM.

test/Analysis/number-object-conversion.m
98 ↗(On Diff #76043)

This is great! And a good catch.

This revision was automatically updated to reflect the committed changes.