summaryrefslogtreecommitdiff
path: root/test/SemaObjCXX/properties.mm
blob: 7bb4fab3d3fd9ff662ffbbce2459a65016cac288 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-objc-root-class %s

struct X { 
  void f() const;
  ~X();
};

@interface A {
  X x_;
}

- (const X&)x;
- (void)setx:(const X&)other;
@end

@implementation A

- (const X&)x { return x_; }
- (void)setx:(const X&)other { x_ = other; }
- (void)method {
  self.x.f();
}
@end

// rdar://problem/10444030
@interface Test2
- (void) setY: (int) y;
- (int) z;
@end
void test2(Test2 *a) {
  auto y = a.y; // expected-error {{no getter method for read from property}}
  auto z = a.z;
}

// rdar://problem/10672108
@interface Test3
- (int) length;
@end
void test3(Test3 *t) {
  char vla[t.length] = {}; // expected-error {{variable-sized object may not be initialized}}
  char *heaparray = new char[t.length];
}

// <rdar://problem/10672501>
namespace std {
  template<typename T> void count();
}

@interface Test4
- (X&) prop;
@end

void test4(Test4 *t) {
  (void)const_cast<const X&>(t.prop);
  (void)dynamic_cast<X&>(t.prop);
  (void)reinterpret_cast<int&>(t.prop);
}

@interface Test5 {
@public
  int count;
}
@property int count;
@end

void test5(Test5* t5) {
  if (t5.count < 2) { }
  if (t5->count < 2) { }
}


@interface Test6
+ (Class)class;
- (Class)class;
@end

void test6(Test6 *t6) {
  Class x = t6.class;
  Class x2 = Test6.class;
}

template<typename T>
void test6_template(T *t6) {
  Class x = t6.class;
}

template void test6_template(Test6*);

// rdar://problem/10965735
struct Test7PointerMaker {
  operator char *() const;
};
@interface Test7
- (char*) implicit_property;
- (char) bad_implicit_property;
- (Test7PointerMaker) implicit_struct_property;
@property int *explicit_property;
@property int bad_explicit_property;
@property Test7PointerMaker explicit_struct_property;
@end
void test7(Test7 *ptr) {
  delete ptr.implicit_property;
  delete ptr.bad_implicit_property; // expected-error {{cannot delete expression of type 'char'}}
  delete ptr.explicit_property;
  delete ptr.bad_explicit_property; // expected-error {{cannot delete expression of type 'int'}}
  delete ptr.implicit_struct_property;
  delete ptr.explicit_struct_property;
}

// Make sure the returned value from property assignment is void,
// because there isn't any other viable way to handle it for
// non-trivial classes.
class NonTrivial1 {
public:
	~NonTrivial1();
};
class NonTrivial2 {
public:
	NonTrivial2();
	NonTrivial2(const NonTrivial2&);
};
@interface TestNonTrivial
@property(assign, nonatomic) NonTrivial1 p1;
@property(assign, nonatomic) NonTrivial2 p2;
@end
TestNonTrivial *TestNonTrivialObj;

extern void* VoidType;
extern decltype(TestNonTrivialObj.p1 = NonTrivial1())* VoidType;
extern decltype(TestNonTrivialObj.p2 = NonTrivial2())* VoidType;

// rdar://13332183
namespace test9 {
  struct CString {
    const char *_data;
    char operator[](int i) const { return _data[i]; }
  };
}
@interface Test9
@property test9::CString name;
@end
namespace test9 {
  char test(Test9 *t) {
    return t.name[0];
  }
}

namespace test10 {
  struct A { operator const char*(); };
  struct B { operator const char*(); };
}
@interface Test10
@property test10::A a;
@property test10::B b;
@property int index;
@end
namespace test10 {
  void test(Test10 *t) {
    (void) t.a[6];
    (void) 6[t.b];
    (void) "help"[t.index];
    (void) t.index["help"];
    (void) t.a[t.index];
    (void) t.index[t.b];
  }
}

// <rdar://problem/14354144>
@interface PropertyOfItself
@property (readonly, nonatomic) PropertyOfItself x; // expected-error {{interface type cannot be statically allocated}}
@end
@implementation PropertyOfItself
@synthesize x;
@end

// rdar://14654207
struct CGSize {
  double width;
  double height;
};
typedef struct CGSize CGSize;

struct CGRect {
  CGSize origin;
  CGSize size;
};
typedef struct CGRect CGRect;

typedef CGRect NSRect;
void HappySetFrame(NSRect frame) {}

__attribute__((objc_root_class))
@interface NSObject 
@property CGRect frame;
@end

@implementation NSObject
- (void) nothing
{
	HappySetFrame({{0,0}, {13,14}});
	[self setFrame: {{0,0}, {13,14}}];
        self.frame = {{0,0}, {13,14}};
        self.frame = (CGRect){{3,5}, {13,14}};
}
@end