[cfe-commits] r160991 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h lib/StaticAnalyzer/Core/CallEvent.cpp lib/StaticAnalyzer/Core/ProgramState.cpp lib/StaticAnalyzer/Core/Store.cpp test/Analysis/inlining/InlineObjCInstanceMethod.h test/Analysis/inlining/InlineObjCInstanceMethod.m

Anna Zaks ganna at apple.com
Mon Jul 30 13:31:29 PDT 2012


Author: zaks
Date: Mon Jul 30 15:31:29 2012
New Revision: 160991

URL: http://llvm.org/viewvc/llvm-project?rev=160991&view=rev
Log:
[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).

Added:
    cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.h
    cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
    cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=160991&r1=160990&r2=160991&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Mon Jul 30 15:31:29 2012
@@ -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;

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=160991&r1=160990&r2=160991&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon Jul 30 15:31:29 2012
@@ -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).
   //==---------------------------------------------------------------------==//

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=160991&r1=160990&r2=160991&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Jul 30 15:31:29 2012
@@ -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);
-
-    // 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);
+const Decl *ObjCMethodCall::getRuntimeDefinition() const {
+  const ObjCMessageExpr *E = getOriginExpr();
+  Selector Sel = E->getSelector();
+  assert(E);
+
+  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;
 }
 
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=160991&r1=160990&r2=160991&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Mon Jul 30 15:31:29 2012
@@ -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();
+}

Modified: cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp?rev=160991&r1=160990&r2=160991&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp Mon Jul 30 15:31:29 2012
@@ -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;
 }
 

Added: cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.h?rev=160991&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.h (added)
+++ cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.h Mon Jul 30 15:31:29 2012
@@ -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;
+ at protocol NSObject  - (BOOL)isEqual:(id)object; @end
+ at interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+ at end

Added: cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m?rev=160991&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m (added)
+++ cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m Mon Jul 30 15:31:29 2012
@@ -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.
+ at interface MyParent : NSObject
+- (int)getInt;
+ at end
+ at implementation MyParent
+- (int)getInt {
+    return 0;
+}
+ at end
+
+ at interface MyClass : MyParent
+ at end
+ at 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
+}
+
+ at end
+
+// TODO: When method is inlined, the attribute reset should be visible.
+ at interface TestSettingAnAttributeInCallee : NSObject {
+  int _attribute;
+}
+  - (void) method2;
+ at end
+
+ at implementation TestSettingAnAttributeInCallee
+- (int) method1 {
+  [self method2];
+  return 5/_attribute; // expected-warning {{Division by zero}}
+}
+
+- (void) method2 {
+  _attribute = 0;
+}
+ at end
+
+ at interface TestSettingAnAttributeInCaller : NSObject {
+  int _attribute;
+}
+  - (int) method2;
+ at end
+
+ at implementation TestSettingAnAttributeInCaller
+- (void) method1 {
+  _attribute = 0;
+  [self method2];
+}
+
+- (int) method2 {
+  return 5/_attribute; // expected-warning {{Division by zero}}
+}
+ at end
\ No newline at end of file





More information about the cfe-commits mailing list