This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Support inlining of '[self classMethod]' and '[[self class] classMethod]'
ClosedPublic

Authored by zaks.anna on Jan 9 2017, 3:20 PM.

Diff Detail

Repository
rL LLVM

Event Timeline

zaks.anna updated this revision to Diff 83720.Jan 9 2017, 3:20 PM
zaks.anna retitled this revision from to [analyzer] Support inlining of '[self classMethod]' and '[[self class] classMethod]' .
zaks.anna updated this object.
zaks.anna added reviewers: dergachev.a, dcoughlin.
zaks.anna added a subscriber: cfe-commits.
dcoughlin added inline comments.Jan 9 2017, 6:41 PM
lib/StaticAnalyzer/Core/CallEvent.cpp
972 ↗(On Diff #83720)

Here is a case where dispatching via the compile-time type of E is not safe:

#import <Foundation/Foundation.h>

void clang_analyzer_eval(int);

@interface Parent : NSObject
+ (int)a;
+ (int)b;
@end

@interface Child : Parent
@end

@interface Other : NSObject
+(void)run;
@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    [Other run];
  }
  return 0;
}

@implementation Other
+(void)run {
  int result = [Child a];

  clang_analyzer_eval(result == 12);
  printf("result is %d\n", result);
}
@end

@implementation Parent
+ (int)a; {
  return [self b];
}
+ (int)b; {
  return 12;
}
@end

@implementation Child
+ (int)b; {
  return 100;
}
@end

Running this code will print 'result is 100' but the clang_analyzer_eval() will incorrectly yield 'TRUE'.

What do you think about adding a new SVal for ObjC 'Class' values that know what interface declaration they come from? Then 'self' in a class method would be filled in with something meaningful in ObjCMethodCall::getReceiverSVal() and we could do proper dynamic dispatch for class methods just like we do for instance methods now.

977 ↗(On Diff #83720)

accosiate-->associate

test/Analysis/inlining/InlineObjCClassMethod.m
269 ↗(On Diff #83720)

I think it would be good to duplicate some of these tests in -(void)instanceMethod since calling [self class] is most-commonly used in instance methods:

unsigned result2 = [[self class] returns30];
clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
unsigned result3 = [[super class] returns30];
clang_analyzer_eval(result3 == 100); // expected-warning{{UNKNOWN}}
This revision was automatically updated to reflect the committed changes.