[Background: Currently we're trying to eliminate the concept of "transfer functions" from the static analyzer, which has gradually been supplanted by the Checker interface. The only implementation of the transfer functions, CFRefCount, has two roles: general-purpose function and method evaluator, and retain-count checking for the Cocoa and CoreFoundation frameworks. The former is being moved to ExprEngine*, the latter to a regular checker called RetainReleaseChecker. Of course, there are always design issues; I'm trying to make sure they get cleared up on-list one by one.]
After recent patches, I've managed to separate the generic evaluation of functions and Objective-C messages -- basically, invalidating the arguments, implicit 'this' or message receiver, and globals -- from the specific retain-count-related effects of a couple functions. This felt like quite a major step forwards in the transition; everything else is just a sort of extrication and working out couplings that shouldn't exist.
One of those couplings, however, is that the /reference counts/ of arguments and message receivers should /not/ be invalidated on a call...but the reference counts of any /members/ should be. This is currently accomplished by use of a private shared "whitelist" of top-level symbols in a function call, set up by the transfer functions and then used by the RetainReleaseChecker. If the RetainReleaseChecker is to lose its privileged status, it won't be able to know which symbols should have their bindings preserved.
I'm pretty stuck on this one, but I came up with a few possibilities:
1. Restore bindings in a post-call check by walking backwards in the graph to before the call's return value is set.
2. Add the current statement to the checkRegionChanges callback, which would enable RetainReleaseChecker to skip arguments and receivers.
3. Instead of using checkRegionChanges to handle bindings of objects passed by reference, just explicitly stop tracking anything passed by reference in a post-call check. Needs fleshing out for structs, C++ constructors, etc though.
I think the first way is the cleanest, but it's certainly extra work.