Home | History | Annotate | Download | only in SemaObjC
      1 // RUN: %clang_cc1 -fsyntax-only -verify %s
      2 
      3 #if !__has_feature(objc_instancetype)
      4 # error Missing 'instancetype' feature macro.
      5 #endif
      6 
      7 @interface Root
      8 + (instancetype)alloc; // expected-note {{explicitly declared 'instancetype'}}
      9 - (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
     10 - (instancetype)self; // expected-note {{explicitly declared 'instancetype'}}
     11 - (Class)class;
     12 
     13 @property (assign) Root *selfProp;
     14 - (instancetype)selfProp;
     15 @end
     16 
     17 @protocol Proto1
     18 @optional
     19 - (instancetype)methodInProto1;
     20 @end
     21 
     22 @protocol Proto2
     23 @optional
     24 - (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}}
     25 - (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
     26 @end
     27 
     28 @interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}}
     29 - (instancetype)initSubclass1;
     30 - (void)methodOnSubclass1;
     31 + (instancetype)allocSubclass1;
     32 @end
     33 
     34 @interface Subclass2 : Root
     35 - (instancetype)initSubclass2;
     36 - (void)methodOnSubclass2;
     37 @end
     38 
     39 // Sanity check: the basic initialization pattern.
     40 void test_instancetype_alloc_init_simple() {
     41   Root *r1 = [[Root alloc] init];
     42   Subclass1 *sc1 = [[Subclass1 alloc] init];
     43 }
     44 
     45 // Test that message sends to instancetype methods have the right type.
     46 void test_instancetype_narrow_method_search() {
     47   // instancetype on class methods
     48   Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
     49   Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay
     50 
     51   // instancetype on instance methods
     52   [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}}
     53   [[[Subclass2 alloc] init] methodOnSubclass2];
     54   
     55   // instancetype on class methods using protocols
     56   typedef Subclass1<Proto1> SC1Proto1;
     57   typedef Subclass1<Proto2> SC1Proto2;
     58   [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
     59   [[SC1Proto2 alloc] methodInProto2];
     60 
     61   // instancetype on instance methods
     62   Subclass1<Proto1> *sc1proto1 = 0;
     63   [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
     64   Subclass1<Proto2> *sc1proto2 = 0;
     65   [[sc1proto2 self] methodInProto2];
     66 
     67   // Exact type checks
     68   typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0;
     69   typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0;
     70 
     71   // Message sends to Class.
     72   Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init];
     73 
     74   // Property access
     75   [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
     76   [sc1proto2.self methodInProto2];
     77   [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
     78   [Subclass2.alloc initSubclass2];
     79 
     80   [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
     81   [sc1proto2.selfProp methodInProto2];
     82 }
     83 
     84 // Test that message sends to super methods have the right type.
     85 @interface Subsubclass1 : Subclass1
     86 - (instancetype)initSubclass1;
     87 + (instancetype)allocSubclass1;
     88 
     89 - (void)onlyInSubsubclass1;
     90 @end
     91 
     92 @implementation Subsubclass1
     93 - (instancetype)initSubclass1 {
     94   // Check based on method search.
     95   [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
     96   [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
     97 
     98   self = [super init]; // common pattern
     99 
    100   // Exact type check.
    101   typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0;
    102 
    103   return self;
    104 }
    105 
    106 + (instancetype)allocSubclass1 {
    107   // Check based on method search.
    108   [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
    109 
    110   // The ASTs don't model super property accesses well enough to get this right
    111   [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
    112 
    113   // Exact type check.
    114   typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0;
    115   
    116   return [super allocSubclass1];
    117 }
    118 
    119 - (void)onlyInSubsubclass1 {}
    120 @end
    121 
    122 // Check compatibility rules for inheritance of related return types.
    123 @class Subclass4;
    124 
    125 @interface Subclass3 <Proto1, Proto2>
    126 - (Subclass3 *)methodInProto1;
    127 - (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}}
    128 @end
    129 
    130 @interface Subclass4 : Root
    131 + (Subclass4 *)alloc; // okay
    132 - (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
    133 - (id)self; // expected-note{{overridden method is part of the 'self' method family}}
    134 - (instancetype)initOther;
    135 @end
    136 
    137 @protocol Proto3 <Proto1, Proto2>
    138 @optional
    139 - (id)methodInProto1;
    140 - (Subclass1 *)methodInProto2;
    141 - (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
    142 @end
    143 
    144 @implementation Subclass4
    145 + (id)alloc {
    146   return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}}
    147 }
    148 
    149 - (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
    150 
    151 - (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
    152 
    153 - (Subclass4 *)initOther { return 0; }
    154 
    155 @end
    156 
    157 // Check that inherited related return types influence the types of
    158 // message sends.
    159 void test_instancetype_inherited() {
    160   [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}}
    161   [[Subclass4 alloc] initOther];
    162 }
    163 
    164 // Check that related return types tighten up the semantics of
    165 // Objective-C method implementations.
    166 @implementation Subclass2
    167 - (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}}
    168   Subclass1 *sc1 = [[Subclass1 alloc] init];
    169   return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
    170 }
    171 - (void)methodOnSubclass2 {}
    172 - (id)self {
    173   Subclass1 *sc1 = [[Subclass1 alloc] init];
    174   return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
    175 }
    176 @end
    177 
    178 @interface MyClass : Root
    179 + (int)myClassMethod;
    180 @end
    181 
    182 @implementation MyClass
    183 + (int)myClassMethod { return 0; }
    184 
    185 - (void)blah {
    186   int i = [[MyClass self] myClassMethod];
    187 }
    188 
    189 @end
    190 
    191 // rdar://12493140
    192 @protocol P4
    193 - (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
    194 @end
    195 @interface A4 : Root <P4>
    196 - (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
    197 - (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}}
    198 @end
    199 @interface B4 : Root @end
    200 
    201 @implementation A4 {
    202   B4 *_b;
    203 }
    204 - (id) foo {
    205   return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}}
    206 }
    207 - (id) bar {
    208   return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}}
    209 }
    210 
    211 // This is really just to ensure that we don't crash.
    212 // FIXME: only one diagnostic, please
    213 - (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}}
    214   return 0;
    215 }
    216 @end
    217