@@ -896,6 +896,38 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
896
896
llvm_unreachable (" The while loop should always terminate." );
897
897
}
898
898
899
+ static const ObjCMethodDecl *findDefiningRedecl (const ObjCMethodDecl *MD) {
900
+ if (!MD)
901
+ return MD;
902
+
903
+ // Find the redeclaration that defines the method.
904
+ if (!MD->hasBody ()) {
905
+ for (auto I : MD->redecls ())
906
+ if (I->hasBody ())
907
+ MD = cast<ObjCMethodDecl>(I);
908
+ }
909
+ return MD;
910
+ }
911
+
912
+ static bool isCallToSelfClass (const ObjCMessageExpr *ME) {
913
+ const Expr* InstRec = ME->getInstanceReceiver ();
914
+ if (!InstRec)
915
+ return false ;
916
+ const auto *InstRecIg = dyn_cast<DeclRefExpr>(InstRec->IgnoreParenImpCasts ());
917
+
918
+ // Check that receiver is called 'self'.
919
+ if (!InstRecIg || !InstRecIg->getFoundDecl () ||
920
+ !InstRecIg->getFoundDecl ()->getName ().equals (" self" ))
921
+ return false ;
922
+
923
+ // Check that the method name is 'class'.
924
+ if (ME->getSelector ().getNumArgs () != 0 ||
925
+ !ME->getSelector ().getNameForSlot (0 ).equals (" class" ))
926
+ return false ;
927
+
928
+ return true ;
929
+ }
930
+
899
931
RuntimeDefinition ObjCMethodCall::getRuntimeDefinition () const {
900
932
const ObjCMessageExpr *E = getOriginExpr ();
901
933
assert (E);
@@ -910,6 +942,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
910
942
const MemRegion *Receiver = nullptr ;
911
943
912
944
if (!SupersType.isNull ()) {
945
+ // The receiver is guaranteed to be 'super' in this case.
913
946
// Super always means the type of immediate predecessor to the method
914
947
// where the call occurs.
915
948
ReceiverT = cast<ObjCObjectPointerType>(SupersType);
@@ -921,15 +954,40 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
921
954
DynamicTypeInfo DTI = getDynamicTypeInfo (getState (), Receiver);
922
955
QualType DynType = DTI.getType ();
923
956
CanBeSubClassed = DTI.canBeASubClass ();
924
- ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType);
957
+ ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType. getCanonicalType () );
925
958
926
959
if (ReceiverT && CanBeSubClassed)
927
960
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl ())
928
961
if (!canBeOverridenInSubclass (IDecl, Sel))
929
962
CanBeSubClassed = false ;
930
963
}
931
964
932
- // Lookup the method implementation.
965
+ // Handle special cases of '[self classMethod]' and
966
+ // '[[self class] classMethod]', which are treated by the compiler as
967
+ // instance (not class) messages. We will statically dispatch to those.
968
+ if (auto *PT = dyn_cast_or_null<ObjCObjectPointerType>(ReceiverT)) {
969
+ // For [self classMethod], return the compiler visible declaration.
970
+ if (PT->getObjectType ()->isObjCClass () &&
971
+ Receiver == getSelfSVal ().getAsRegion ())
972
+ return RuntimeDefinition (findDefiningRedecl (E->getMethodDecl ()));
973
+
974
+ // Similarly, handle [[self class] classMethod].
975
+ // TODO: We are currently doing a syntactic match for this pattern with is
976
+ // limiting as the test cases in Analysis/inlining/InlineObjCClassMethod.m
977
+ // shows. A better way would be to associate the meta type with the symbol
978
+ // using the dynamic type info tracking and use it here. We can add a new
979
+ // SVal for ObjC 'Class' values that know what interface declaration they
980
+ // come from. Then 'self' in a class method would be filled in with
981
+ // something meaningful in ObjCMethodCall::getReceiverSVal() and we could
982
+ // do proper dynamic dispatch for class methods just like we do for
983
+ // instance methods now.
984
+ if (E->getInstanceReceiver ())
985
+ if (const auto *M = dyn_cast<ObjCMessageExpr>(E->getInstanceReceiver ()))
986
+ if (isCallToSelfClass (M))
987
+ return RuntimeDefinition (findDefiningRedecl (E->getMethodDecl ()));
988
+ }
989
+
990
+ // Lookup the instance method implementation.
933
991
if (ReceiverT)
934
992
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl ()) {
935
993
// Repeatedly calling lookupPrivateMethod() is expensive, especially
0 commit comments