[analyzer] Very simple ObjC instance method inlining

- Retrieves the type of the object/receiver from the state.
- Binds self during stack setup.
- Only explores the path on which the method is inlined (no
bifurcation to explore the path on which the method is not inlined).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160991 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 97612d6..74ac253 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -695,8 +695,6 @@
   virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
 
   virtual QualType getDeclaredResultType() const;
-  ObjCMethodDecl *LookupClassMethodDefinition(Selector Sel,
-                                           ObjCInterfaceDecl *ClassDecl) const;
 
 public:
   virtual const ObjCMessageExpr *getOriginExpr() const {
@@ -752,22 +750,7 @@
   // TODO: We might want to only compute this once (or change the API for 
   // getting the parameters). Currently, this gets called 3 times during 
   // inlining.
-  virtual const Decl *getRuntimeDefinition() const {
-    const ObjCMessageExpr *E = getOriginExpr();
-    assert(E);
-
-    if (E->isInstanceMessage()) {
-      return 0;
-    } else {
-      // This is a class method.
-      // If we have type info for the receiver class, we are calling via
-      // class name.
-      if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface())
-        return LookupClassMethodDefinition(E->getSelector(), IDecl);
-    }
-
-    return 0;
-  }
+  virtual const Decl *getRuntimeDefinition() const;
 
   virtual param_iterator param_begin(bool UseDefinitionParams = false) const;
   virtual param_iterator param_end(bool UseDefinitionParams = false) const;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 0d1579f..4e92873 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -56,6 +56,18 @@
   }
 };
 
+/// \class Stores the dynamic type information.
+/// Information about type of an object at runtime. This is used by dynamic
+/// dispatch implementation.
+class DynamicTypeInfo {
+  QualType T;
+
+public:
+  DynamicTypeInfo() : T(QualType()) {}
+  DynamicTypeInfo(QualType WithType) : T(WithType) {}
+  QualType getType() {return T;}
+};
+
 /// \class ProgramState
 /// ProgramState - This class encapsulates:
 ///
@@ -313,6 +325,9 @@
   bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
   bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
 
+  /// Get dynamic type information for a region.
+  DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const;
+
   //==---------------------------------------------------------------------==//
   // Accessing the Generic Data Map (GDM).
   //==---------------------------------------------------------------------==//
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index ab4b383..6a5d0f0 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -590,34 +590,34 @@
   return static_cast<ObjCMessageKind>(Info.getInt());
 }
 
-// TODO: This implementation is copied from SemaExprObjC.cpp, needs to be
-// factored into the ObjCInterfaceDecl.
-ObjCMethodDecl *ObjCMethodCall::LookupClassMethodDefinition(Selector Sel,
-                                           ObjCInterfaceDecl *ClassDecl) const {
-  ObjCMethodDecl *Method = 0;
-  // Lookup in class and all superclasses.
-  while (ClassDecl && !Method) {
-    if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
-      Method = ImpDecl->getClassMethod(Sel);
+const Decl *ObjCMethodCall::getRuntimeDefinition() const {
+  const ObjCMessageExpr *E = getOriginExpr();
+  Selector Sel = E->getSelector();
+  assert(E);
 
-    // Look through local category implementations associated with the class.
-    if (!Method)
-      Method = ClassDecl->getCategoryClassMethod(Sel);
-
-    // Before we give up, check if the selector is an instance method.
-    // But only in the root. This matches gcc's behavior and what the
-    // runtime expects.
-    if (!Method && !ClassDecl->getSuperClass()) {
-      Method = ClassDecl->lookupInstanceMethod(Sel);
-      // Look through local category implementations associated
-      // with the root class.
-      //if (!Method)
-      //  Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+  if (E->isInstanceMessage()) {
+    const MemRegion *Receiver = getReceiverSVal().getAsRegion();
+    DynamicTypeInfo TI = getState()->getDynamicTypeInfo(Receiver);
+    const ObjCObjectPointerType *T =
+                    dyn_cast<ObjCObjectPointerType>(TI.getType().getTypePtr());
+    if (!T)
+      return 0;
+    if (ObjCInterfaceDecl *IDecl = T->getInterfaceDecl()) {
+      // Find the method implementation.
+      return IDecl->lookupPrivateMethod(Sel);
     }
 
-    ClassDecl = ClassDecl->getSuperClass();
+  } else {
+    // This is a class method.
+    // If we have type info for the receiver class, we are calling via
+    // class name.
+    if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface()) {
+      // Find/Return the method implementation.
+      return IDecl->lookupPrivateClassMethod(Sel);
+    }
   }
-  return Method;
+
+  return 0;
 }
 
 
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 6adc18c..20f1e22 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -731,3 +731,12 @@
   
   return Tainted;
 }
+
+DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
+  if (const TypedRegion *TR = dyn_cast<TypedRegion>(Reg))
+    return DynamicTypeInfo(TR->getLocationType());
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
+    return DynamicTypeInfo(SR->getSymbol()
+                             ->getType(getStateManager().getContext()));
+  return DynamicTypeInfo();
+}
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 98d815f..ed221c5 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -53,6 +53,13 @@
     Store = Bind(Store.getStore(), ThisRegion, ThisVal);
   }
 
+  if (const ObjCMethodCall *MCall = dyn_cast<ObjCMethodCall>(&Call)) {
+    SVal SelfVal = MCall->getReceiverSVal();
+    const VarDecl *SelfDecl = LCtx->getAnalysisDeclContext()->getSelfDecl();
+    Store = Bind(Store.getStore(),
+                 svalBuilder.makeLoc(MRMgr.getVarRegion(SelfDecl, LCtx)),
+                 SelfVal);
+  }
   return Store;
 }
 
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.h b/test/Analysis/inlining/InlineObjCInstanceMethod.h
new file mode 100644
index 0000000..18131c8
--- /dev/null
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.h
@@ -0,0 +1,19 @@
+
+// Define a public header for the ObjC methods that are "visible" externally
+// and, thus, could be sub-classed. We should explore the path on which these
+// are sub-classed with unknown class by not inlining them.
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+    Class isa;
+} *id;
+@protocol NSObject  - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.m b/test/Analysis/inlining/InlineObjCInstanceMethod.m
new file mode 100644
index 0000000..682d02a
--- /dev/null
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.m
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic -verify %s
+
+#include "InlineObjCInstanceMethod.h"
+
+// Method is defined in the parent; called through self.
+@interface MyParent : NSObject
+- (int)getInt;
+@end
+@implementation MyParent
+- (int)getInt {
+    return 0;
+}
+@end
+
+@interface MyClass : MyParent
+@end
+@implementation MyClass
+- (int)testDynDispatchSelf {
+  int y = [self getInt];
+  return 5/y; // expected-warning {{Division by zero}}
+}
+
+// Method is called on inited object.
++ (int)testAllocInit {
+  MyClass *a = [[self alloc] init];
+  return 5/[a getInt]; // todo
+}
+
+// Method is called on inited object.
++ (int)testAllocInit2 {
+  MyClass *a = [[MyClass alloc] init];
+  return 5/[a getInt]; // todo
+}
+
+// Method is called on a parameter.
++ (int)testParam: (MyClass*) a {
+  return 5/[a getInt]; // expected-warning {{Division by zero}}
+}
+
+// Method is called on a parameter of unnown type.
++ (int)testParamUnknownType: (id) a {
+  return 5/[a getInt]; // no warning
+}
+
+@end
+
+// TODO: When method is inlined, the attribute reset should be visible.
+@interface TestSettingAnAttributeInCallee : NSObject {
+  int _attribute;
+}
+  - (void) method2;
+@end
+
+@implementation TestSettingAnAttributeInCallee
+- (int) method1 {
+  [self method2];
+  return 5/_attribute; // expected-warning {{Division by zero}}
+}
+
+- (void) method2 {
+  _attribute = 0;
+}
+@end
+
+@interface TestSettingAnAttributeInCaller : NSObject {
+  int _attribute;
+}
+  - (int) method2;
+@end
+
+@implementation TestSettingAnAttributeInCaller
+- (void) method1 {
+  _attribute = 0;
+  [self method2];
+}
+
+- (int) method2 {
+  return 5/_attribute; // expected-warning {{Division by zero}}
+}
+@end
\ No newline at end of file