 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
81.7% |
414 / 507 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
98.8% |
501 / 507 |
| |
|
Line Coverage: |
90.6% |
788 / 870 |
| |
 |
|
 |
1 : //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file implements the Objective-C portions of the Parser interface.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/Parse/Parser.h"
15 : #include "clang/Parse/DeclSpec.h"
16 : #include "clang/Parse/Scope.h"
17 : #include "clang/Parse/ParseDiagnostic.h"
18 : #include "llvm/ADT/SmallVector.h"
19 : using namespace clang;
20 :
21 :
22 : /// ParseObjCAtDirectives - Handle parts of the external-declaration production:
23 : /// external-declaration: [C99 6.9]
24 : /// [OBJC] objc-class-definition
25 : /// [OBJC] objc-class-declaration
26 : /// [OBJC] objc-alias-declaration
27 : /// [OBJC] objc-protocol-definition
28 : /// [OBJC] objc-method-definition
29 : /// [OBJC] '@' 'end'
30 4381: Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
31 4381: SourceLocation AtLoc = ConsumeToken(); // the "@"
32 :
2: branch 1 taken
4379: branch 2 taken
33 4381: if (Tok.is(tok::code_completion)) {
34 2: Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false);
35 2: ConsumeToken();
36 : }
37 :
391: branch 1 taken
1738: branch 2 taken
730: branch 3 taken
652: branch 4 taken
633: branch 5 taken
10: branch 6 taken
167: branch 7 taken
58: branch 8 taken
2: branch 9 taken
38 4381: switch (Tok.getObjCKeywordID()) {
39 : case tok::objc_class:
40 391: return ParseObjCAtClassDeclaration(AtLoc);
41 : case tok::objc_interface:
42 1738: return ParseObjCAtInterfaceDeclaration(AtLoc);
43 : case tok::objc_protocol:
44 730: return ParseObjCAtProtocolDeclaration(AtLoc);
45 : case tok::objc_implementation:
46 652: return ParseObjCAtImplementationDeclaration(AtLoc);
47 : case tok::objc_end:
48 633: return ParseObjCAtEndDeclaration(AtLoc);
49 : case tok::objc_compatibility_alias:
50 10: return ParseObjCAtAliasDeclaration(AtLoc);
51 : case tok::objc_synthesize:
52 167: return ParseObjCPropertySynthesize(AtLoc);
53 : case tok::objc_dynamic:
54 58: return ParseObjCPropertyDynamic(AtLoc);
55 : default:
56 2: Diag(AtLoc, diag::err_unexpected_at);
57 2: SkipUntil(tok::semi);
58 2: return DeclPtrTy();
59 : }
60 : }
61 :
62 : ///
63 : /// objc-class-declaration:
64 : /// '@' 'class' identifier-list ';'
65 : ///
66 391: Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
67 391: ConsumeToken(); // the identifier "class"
68 391: llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
69 391: llvm::SmallVector<SourceLocation, 8> ClassLocs;
70 :
71 :
72 867: while (1) {
0: branch 1 not taken
1258: branch 2 taken
73 1258: if (Tok.isNot(tok::identifier)) {
74 0: Diag(Tok, diag::err_expected_ident);
75 0: SkipUntil(tok::semi);
76 0: return DeclPtrTy();
77 : }
78 1258: ClassNames.push_back(Tok.getIdentifierInfo());
79 1258: ClassLocs.push_back(Tok.getLocation());
80 1258: ConsumeToken();
81 :
867: branch 1 taken
391: branch 2 taken
82 1258: if (Tok.isNot(tok::comma))
83 391: break;
84 :
85 867: ConsumeToken();
86 : }
87 :
88 : // Consume the ';'.
0: branch 1 not taken
391: branch 2 taken
89 391: if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
90 0: return DeclPtrTy();
91 :
92 : return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
93 : ClassLocs.data(),
94 391: ClassNames.size());
95 : }
96 :
97 : ///
98 : /// objc-interface:
99 : /// objc-class-interface-attributes[opt] objc-class-interface
100 : /// objc-category-interface
101 : ///
102 : /// objc-class-interface:
103 : /// '@' 'interface' identifier objc-superclass[opt]
104 : /// objc-protocol-refs[opt]
105 : /// objc-class-instance-variables[opt]
106 : /// objc-interface-decl-list
107 : /// @end
108 : ///
109 : /// objc-category-interface:
110 : /// '@' 'interface' identifier '(' identifier[opt] ')'
111 : /// objc-protocol-refs[opt]
112 : /// objc-interface-decl-list
113 : /// @end
114 : ///
115 : /// objc-superclass:
116 : /// ':' identifier
117 : ///
118 : /// objc-class-interface-attributes:
119 : /// __attribute__((visibility("default")))
120 : /// __attribute__((visibility("hidden")))
121 : /// __attribute__((deprecated))
122 : /// __attribute__((unavailable))
123 : /// __attribute__((objc_exception)) - used by NSException on 64-bit
124 : ///
125 : Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
126 1753: SourceLocation atLoc, AttributeList *attrList) {
127 : assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
1753: branch 1 taken
0: branch 2 not taken
128 1753: "ParseObjCAtInterfaceDeclaration(): Expected @interface");
129 1753: ConsumeToken(); // the "interface" identifier
130 :
131 : // Code completion after '@interface'.
2: branch 1 taken
1751: branch 2 taken
132 1753: if (Tok.is(tok::code_completion)) {
133 2: Actions.CodeCompleteObjCInterfaceDecl(CurScope);
134 2: ConsumeToken();
135 : }
136 :
2: branch 1 taken
1751: branch 2 taken
137 1753: if (Tok.isNot(tok::identifier)) {
138 2: Diag(Tok, diag::err_expected_ident); // missing class or category name.
139 2: return DeclPtrTy();
140 : }
141 :
142 : // We have a class or category name - consume it.
143 1751: IdentifierInfo *nameId = Tok.getIdentifierInfo();
144 1751: SourceLocation nameLoc = ConsumeToken();
145 :
189: branch 1 taken
1562: branch 2 taken
146 1751: if (Tok.is(tok::l_paren)) { // we have a category.
147 189: SourceLocation lparenLoc = ConsumeParen();
148 189: SourceLocation categoryLoc, rparenLoc;
149 189: IdentifierInfo *categoryId = 0;
150 :
2: branch 1 taken
187: branch 2 taken
151 189: if (Tok.is(tok::code_completion)) {
152 2: Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId);
153 2: ConsumeToken();
154 : }
155 :
156 : // For ObjC2, the category name is optional (not an error).
158: branch 1 taken
31: branch 2 taken
157 189: if (Tok.is(tok::identifier)) {
158 158: categoryId = Tok.getIdentifierInfo();
159 158: categoryLoc = ConsumeToken();
0: branch 1 not taken
31: branch 2 taken
160 31: } else if (!getLang().ObjC2) {
161 0: Diag(Tok, diag::err_expected_ident); // missing category name.
162 0: return DeclPtrTy();
163 : }
2: branch 1 taken
187: branch 2 taken
164 189: if (Tok.isNot(tok::r_paren)) {
165 2: Diag(Tok, diag::err_expected_rparen);
166 2: SkipUntil(tok::r_paren, false); // don't stop at ';'
167 2: return DeclPtrTy();
168 : }
169 187: rparenLoc = ConsumeParen();
170 :
171 : // Next, we need to check for any protocol references.
172 187: SourceLocation LAngleLoc, EndProtoLoc;
173 187: llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
174 187: llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
18: branch 1 taken
169: branch 2 taken
0: branch 4 not taken
18: branch 5 taken
0: branch 6 not taken
187: branch 7 taken
175 187: if (Tok.is(tok::less) &&
176 : ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
177 : LAngleLoc, EndProtoLoc))
178 0: return DeclPtrTy();
179 :
0: branch 0 not taken
187: branch 1 taken
180 187: if (attrList) // categories don't support attributes.
181 0: Diag(Tok, diag::err_objc_no_attributes_on_category);
182 :
183 : DeclPtrTy CategoryType =
184 : Actions.ActOnStartCategoryInterface(atLoc,
185 : nameId, nameLoc,
186 : categoryId, categoryLoc,
187 : ProtocolRefs.data(),
188 : ProtocolRefs.size(),
189 : ProtocolLocs.data(),
190 187: EndProtoLoc);
191 :
192 187: ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
193 187: return CategoryType;
194 : }
195 : // Parse a class interface.
196 1562: IdentifierInfo *superClassId = 0;
197 1562: SourceLocation superClassLoc;
198 :
733: branch 1 taken
829: branch 2 taken
199 1562: if (Tok.is(tok::colon)) { // a super class is specified.
200 733: ConsumeToken();
201 :
202 : // Code completion of superclass names.
1: branch 1 taken
732: branch 2 taken
203 733: if (Tok.is(tok::code_completion)) {
204 1: Actions.CodeCompleteObjCSuperclass(CurScope, nameId);
205 1: ConsumeToken();
206 : }
207 :
1: branch 1 taken
732: branch 2 taken
208 733: if (Tok.isNot(tok::identifier)) {
209 1: Diag(Tok, diag::err_expected_ident); // missing super class name.
210 1: return DeclPtrTy();
211 : }
212 732: superClassId = Tok.getIdentifierInfo();
213 732: superClassLoc = ConsumeToken();
214 : }
215 : // Next, we need to check for any protocol references.
216 1561: llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs;
217 1561: llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
218 1561: SourceLocation LAngleLoc, EndProtoLoc;
422: branch 1 taken
1139: branch 2 taken
0: branch 4 not taken
422: branch 5 taken
0: branch 6 not taken
1561: branch 7 taken
219 1561: if (Tok.is(tok::less) &&
220 : ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
221 : LAngleLoc, EndProtoLoc))
222 0: return DeclPtrTy();
223 :
224 : DeclPtrTy ClsType =
225 : Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
226 : superClassId, superClassLoc,
227 : ProtocolRefs.data(), ProtocolRefs.size(),
228 : ProtocolLocs.data(),
229 1561: EndProtoLoc, attrList);
230 :
752: branch 1 taken
809: branch 2 taken
231 1561: if (Tok.is(tok::l_brace))
232 752: ParseObjCClassInstanceVariables(ClsType, atLoc);
233 :
234 1561: ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
235 1561: return ClsType;
236 : }
237 :
238 : /// The Objective-C property callback. This should be defined where
239 : /// it's used, but instead it's been lifted to here to support VS2005.
0: branch 1 not taken
0: branch 2 not taken
0: branch 5 not taken
504: branch 6 taken
240 504: struct Parser::ObjCPropertyCallback : FieldCallback {
241 : Parser &P;
242 : DeclPtrTy IDecl;
243 : llvm::SmallVectorImpl<DeclPtrTy> &Props;
244 : ObjCDeclSpec &OCDS;
245 : SourceLocation AtLoc;
246 : tok::ObjCKeywordKind MethodImplKind;
247 :
248 : ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl,
249 : llvm::SmallVectorImpl<DeclPtrTy> &Props,
250 : ObjCDeclSpec &OCDS, SourceLocation AtLoc,
251 504: tok::ObjCKeywordKind MethodImplKind) :
252 : P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
253 504: MethodImplKind(MethodImplKind) {
254 504: }
255 :
256 502: DeclPtrTy invoke(FieldDeclarator &FD) {
7: branch 1 taken
495: branch 2 taken
257 502: if (FD.D.getIdentifier() == 0) {
258 : P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
259 7: << FD.D.getSourceRange();
260 7: return DeclPtrTy();
261 : }
1: branch 0 taken
494: branch 1 taken
262 495: if (FD.BitfieldSize) {
263 : P.Diag(AtLoc, diag::err_objc_property_bitfield)
264 1: << FD.D.getSourceRange();
265 1: return DeclPtrTy();
266 : }
267 :
268 : // Install the property declarator into interfaceDecl.
269 : IdentifierInfo *SelName =
18: branch 1 taken
476: branch 2 taken
270 494: OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
271 :
272 : Selector GetterSel =
273 494: P.PP.getSelectorTable().getNullarySelector(SelName);
274 494: IdentifierInfo *SetterName = OCDS.getSetterName();
275 494: Selector SetterSel;
21: branch 0 taken
473: branch 1 taken
276 494: if (SetterName)
277 21: SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
278 : else
279 : SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(),
280 : P.PP.getSelectorTable(),
281 473: FD.D.getIdentifier());
282 494: bool isOverridingProperty = false;
283 : DeclPtrTy Property =
284 : P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS,
285 : GetterSel, SetterSel, IDecl,
286 : &isOverridingProperty,
287 494: MethodImplKind);
458: branch 0 taken
36: branch 1 taken
288 494: if (!isOverridingProperty)
289 458: Props.push_back(Property);
290 :
291 494: return Property;
292 : }
293 : };
294 :
295 : /// objc-interface-decl-list:
296 : /// empty
297 : /// objc-interface-decl-list objc-property-decl [OBJC2]
298 : /// objc-interface-decl-list objc-method-requirement [OBJC2]
299 : /// objc-interface-decl-list objc-method-proto ';'
300 : /// objc-interface-decl-list declaration
301 : /// objc-interface-decl-list ';'
302 : ///
303 : /// objc-method-requirement: [OBJC2]
304 : /// @required
305 : /// @optional
306 : ///
307 : void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
308 2409: tok::ObjCKeywordKind contextKey) {
309 2409: llvm::SmallVector<DeclPtrTy, 32> allMethods;
310 2409: llvm::SmallVector<DeclPtrTy, 16> allProperties;
311 2409: llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
312 2409: tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
313 :
314 2409: SourceRange AtEnd;
315 :
316 2766: while (1) {
317 : // If this is a method prototype, parse it.
3376: branch 1 taken
1799: branch 2 taken
405: branch 4 taken
2971: branch 5 taken
2204: branch 6 taken
2971: branch 7 taken
318 5175: if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
319 : DeclPtrTy methodPrototype =
320 2204: ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
321 2204: allMethods.push_back(methodPrototype);
322 : // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
323 : // method definitions.
324 : ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
325 2204: "", tok::semi);
326 2204: continue;
327 : }
328 :
329 : // Ignore excess semicolons.
5: branch 1 taken
2966: branch 2 taken
330 2971: if (Tok.is(tok::semi)) {
331 5: ConsumeToken();
332 5: continue;
333 : }
334 :
335 : // If we got to the end of the file, exit the loop.
2957: branch 1 taken
9: branch 2 taken
336 2966: if (Tok.is(tok::eof))
337 9: break;
338 :
339 : // Code completion within an Objective-C interface.
1: branch 1 taken
2956: branch 2 taken
340 2957: if (Tok.is(tok::code_completion)) {
341 : Actions.CodeCompleteOrdinaryName(CurScope,
342 : ObjCImpDecl? Action::CCC_ObjCImplementation
0: branch 1 not taken
1: branch 2 taken
343 1: : Action::CCC_ObjCInterface);
344 1: ConsumeToken();
345 : }
346 :
347 : // If we don't have an @ directive, parse it as a function definition.
14: branch 1 taken
2943: branch 2 taken
348 2957: if (Tok.isNot(tok::at)) {
349 : // The code below does not consume '}'s because it is afraid of eating the
350 : // end of a namespace. Because of the way this code is structured, an
351 : // erroneous r_brace would cause an infinite loop if not handled here.
1: branch 1 taken
13: branch 2 taken
352 14: if (Tok.is(tok::r_brace))
353 1: break;
354 :
355 : // FIXME: as the name implies, this rule allows function definitions.
356 : // We could pass a flag or check for functions during semantic analysis.
357 13: allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0));
358 13: continue;
359 : }
360 :
361 : // Otherwise, we have an @ directive, eat the @.
362 2943: SourceLocation AtLoc = ConsumeToken(); // the "@"
1: branch 1 taken
2942: branch 2 taken
363 2943: if (Tok.is(tok::code_completion)) {
364 1: Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
365 1: ConsumeToken();
366 1: break;
367 : }
368 :
369 2942: tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
370 :
2398: branch 0 taken
544: branch 1 taken
371 2942: if (DirectiveKind == tok::objc_end) { // @end -> terminate list
372 2398: AtEnd.setBegin(AtLoc);
373 2398: AtEnd.setEnd(Tok.getLocation());
374 2398: break;
375 : }
376 :
377 : // Eat the identifier.
378 544: ConsumeToken();
379 :
0: branch 0 not taken
40: branch 1 taken
504: branch 2 taken
380 544: switch (DirectiveKind) {
381 : default:
382 : // FIXME: If someone forgets an @end on a protocol, this loop will
383 : // continue to eat up tons of stuff and spew lots of nonsense errors. It
384 : // would probably be better to bail out if we saw an @class or @interface
385 : // or something like that.
386 0: Diag(AtLoc, diag::err_objc_illegal_interface_qual);
387 : // Skip until we see an '@' or '}' or ';'.
388 0: SkipUntil(tok::r_brace, tok::at);
389 0: break;
390 :
391 : case tok::objc_required:
392 : case tok::objc_optional:
393 : // This is only valid on protocols.
394 : // FIXME: Should this check for ObjC2 being enabled?
2: branch 0 taken
38: branch 1 taken
395 40: if (contextKey != tok::objc_protocol)
396 2: Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
397 : else
398 38: MethodImplKind = DirectiveKind;
399 40: break;
400 :
401 : case tok::objc_property:
0: branch 1 not taken
504: branch 2 taken
402 504: if (!getLang().ObjC2)
403 0: Diag(AtLoc, diag::err_objc_propertoes_require_objc2);
404 :
405 504: ObjCDeclSpec OCDS;
406 : // Parse property attribute list, if any.
352: branch 1 taken
152: branch 2 taken
407 504: if (Tok.is(tok::l_paren))
408 : ParseObjCPropertyAttribute(OCDS, interfaceDecl,
409 352: allMethods.data(), allMethods.size());
410 :
411 : ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties,
412 504: OCDS, AtLoc, MethodImplKind);
413 :
414 : // Parse all the comma separated declarators.
415 504: DeclSpec DS;
416 504: ParseStructDeclaration(DS, Callback);
417 :
418 : ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
419 504: tok::at);
420 504: break;
421 : }
422 : }
423 :
424 : // We break out of the big loop in two cases: when we see @end or when we see
425 : // EOF. In the former case, eat the @end. In the later case, emit an error.
0: branch 1 not taken
2409: branch 2 taken
426 2409: if (Tok.is(tok::code_completion)) {
427 0: Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
428 0: ConsumeToken();
2398: branch 1 taken
11: branch 2 taken
429 2409: } else if (Tok.isObjCAtKeyword(tok::objc_end))
430 2398: ConsumeToken(); // the "end" identifier
431 : else
432 11: Diag(Tok, diag::err_objc_missing_end);
433 :
434 : // Insert collected methods declarations into the @interface object.
435 : // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
436 : Actions.ActOnAtEnd(AtEnd, interfaceDecl,
437 : allMethods.data(), allMethods.size(),
438 : allProperties.data(), allProperties.size(),
439 2409: allTUVariables.data(), allTUVariables.size());
440 2409: }
441 :
442 : /// Parse property attribute declarations.
443 : ///
444 : /// property-attr-decl: '(' property-attrlist ')'
445 : /// property-attrlist:
446 : /// property-attribute
447 : /// property-attrlist ',' property-attribute
448 : /// property-attribute:
449 : /// getter '=' identifier
450 : /// setter '=' identifier ':'
451 : /// readonly
452 : /// readwrite
453 : /// assign
454 : /// retain
455 : /// copy
456 : /// nonatomic
457 : ///
458 : void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
459 : DeclPtrTy *Methods,
460 352: unsigned NumMethods) {
0: branch 1 not taken
352: branch 2 taken
461 352: assert(Tok.getKind() == tok::l_paren);
462 352: SourceLocation LHSLoc = ConsumeParen(); // consume '('
463 :
464 149: while (1) {
2: branch 1 taken
499: branch 2 taken
465 501: if (Tok.is(tok::code_completion)) {
466 2: Actions.CodeCompleteObjCPropertyFlags(CurScope, DS);
467 2: ConsumeToken();
468 : }
469 501: const IdentifierInfo *II = Tok.getIdentifierInfo();
470 :
471 : // If this is not an identifier at all, bail out early.
3: branch 0 taken
498: branch 1 taken
472 501: if (II == 0) {
473 3: MatchRHSPunctuation(tok::r_paren, LHSLoc);
474 3: return;
475 : }
476 :
477 498: SourceLocation AttrName = ConsumeToken(); // consume last attribute name
478 :
110: branch 1 taken
388: branch 2 taken
479 498: if (II->isStr("readonly"))
480 110: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
85: branch 1 taken
303: branch 2 taken
481 388: else if (II->isStr("assign"))
482 85: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
68: branch 1 taken
235: branch 2 taken
483 303: else if (II->isStr("readwrite"))
484 68: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
57: branch 1 taken
178: branch 2 taken
485 235: else if (II->isStr("retain"))
486 57: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
52: branch 1 taken
126: branch 2 taken
487 178: else if (II->isStr("copy"))
488 52: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
80: branch 1 taken
46: branch 2 taken
489 126: else if (II->isStr("nonatomic"))
490 80: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
24: branch 1 taken
22: branch 2 taken
23: branch 4 taken
1: branch 5 taken
45: branch 6 taken
1: branch 7 taken
491 46: else if (II->isStr("getter") || II->isStr("setter")) {
492 : // getter/setter require extra treatment.
0: branch 1 not taken
45: branch 2 taken
493 45: if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "",
494 : tok::r_paren))
495 0: return;
496 :
4: branch 1 taken
41: branch 2 taken
497 45: if (Tok.is(tok::code_completion)) {
2: branch 1 taken
2: branch 2 taken
498 4: if (II->getNameStart()[0] == 's')
499 : Actions.CodeCompleteObjCPropertySetter(CurScope, ClassDecl,
500 2: Methods, NumMethods);
501 : else
502 : Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl,
503 2: Methods, NumMethods);
504 4: ConsumeToken();
505 : }
506 :
4: branch 1 taken
41: branch 2 taken
507 45: if (Tok.isNot(tok::identifier)) {
508 4: Diag(Tok, diag::err_expected_ident);
509 4: SkipUntil(tok::r_paren);
510 4: return;
511 : }
512 :
21: branch 1 taken
20: branch 2 taken
513 41: if (II->getNameStart()[0] == 's') {
514 21: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
515 21: DS.setSetterName(Tok.getIdentifierInfo());
516 21: ConsumeToken(); // consume method name
517 :
0: branch 1 not taken
21: branch 2 taken
518 21: if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
519 : tok::r_paren))
520 0: return;
521 : } else {
522 20: DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
523 20: DS.setGetterName(Tok.getIdentifierInfo());
524 20: ConsumeToken(); // consume method name
525 : }
526 : } else {
527 1: Diag(AttrName, diag::err_objc_expected_property_attr) << II;
528 1: SkipUntil(tok::r_paren);
529 1: return;
530 : }
531 :
149: branch 1 taken
344: branch 2 taken
532 493: if (Tok.isNot(tok::comma))
533 344: break;
534 :
535 149: ConsumeToken();
536 : }
537 :
538 344: MatchRHSPunctuation(tok::r_paren, LHSLoc);
539 : }
540 :
541 : /// objc-method-proto:
542 : /// objc-instance-method objc-method-decl objc-method-attributes[opt]
543 : /// objc-class-method objc-method-decl objc-method-attributes[opt]
544 : ///
545 : /// objc-instance-method: '-'
546 : /// objc-class-method: '+'
547 : ///
548 : /// objc-method-attributes: [OBJC2]
549 : /// __attribute__((deprecated))
550 : ///
551 : Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
552 3128: tok::ObjCKeywordKind MethodImplKind) {
585: branch 1 taken
2543: branch 2 taken
585: branch 4 taken
0: branch 5 not taken
553 3128: assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
554 :
555 3128: tok::TokenKind methodType = Tok.getKind();
556 3128: SourceLocation mLoc = ConsumeToken();
557 :
558 3128: DeclPtrTy MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind);
559 : // Since this rule is used for both method declarations and definitions,
560 : // the caller is (optionally) responsible for consuming the ';'.
561 : return MDecl;
562 : }
563 :
564 : /// objc-selector:
565 : /// identifier
566 : /// one of
567 : /// enum struct union if else while do for switch case default
568 : /// break continue return goto asm sizeof typeof __alignof
569 : /// unsigned long const short volatile signed restrict _Complex
570 : /// in out inout bycopy byref oneway int char float double void _Bool
571 : ///
572 7417: IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
1819: branch 1 taken
5598: branch 2 taken
573 7417: switch (Tok.getKind()) {
574 : default:
575 1819: return 0;
576 : case tok::identifier:
577 : case tok::kw_asm:
578 : case tok::kw_auto:
579 : case tok::kw_bool:
580 : case tok::kw_break:
581 : case tok::kw_case:
582 : case tok::kw_catch:
583 : case tok::kw_char:
584 : case tok::kw_class:
585 : case tok::kw_const:
586 : case tok::kw_const_cast:
587 : case tok::kw_continue:
588 : case tok::kw_default:
589 : case tok::kw_delete:
590 : case tok::kw_do:
591 : case tok::kw_double:
592 : case tok::kw_dynamic_cast:
593 : case tok::kw_else:
594 : case tok::kw_enum:
595 : case tok::kw_explicit:
596 : case tok::kw_export:
597 : case tok::kw_extern:
598 : case tok::kw_false:
599 : case tok::kw_float:
600 : case tok::kw_for:
601 : case tok::kw_friend:
602 : case tok::kw_goto:
603 : case tok::kw_if:
604 : case tok::kw_inline:
605 : case tok::kw_int:
606 : case tok::kw_long:
607 : case tok::kw_mutable:
608 : case tok::kw_namespace:
609 : case tok::kw_new:
610 : case tok::kw_operator:
611 : case tok::kw_private:
612 : case tok::kw_protected:
613 : case tok::kw_public:
614 : case tok::kw_register:
615 : case tok::kw_reinterpret_cast:
616 : case tok::kw_restrict:
617 : case tok::kw_return:
618 : case tok::kw_short:
619 : case tok::kw_signed:
620 : case tok::kw_sizeof:
621 : case tok::kw_static:
622 : case tok::kw_static_cast:
623 : case tok::kw_struct:
624 : case tok::kw_switch:
625 : case tok::kw_template:
626 : case tok::kw_this:
627 : case tok::kw_throw:
628 : case tok::kw_true:
629 : case tok::kw_try:
630 : case tok::kw_typedef:
631 : case tok::kw_typeid:
632 : case tok::kw_typename:
633 : case tok::kw_typeof:
634 : case tok::kw_union:
635 : case tok::kw_unsigned:
636 : case tok::kw_using:
637 : case tok::kw_virtual:
638 : case tok::kw_void:
639 : case tok::kw_volatile:
640 : case tok::kw_wchar_t:
641 : case tok::kw_while:
642 : case tok::kw__Bool:
643 : case tok::kw__Complex:
644 : case tok::kw___alignof:
645 5598: IdentifierInfo *II = Tok.getIdentifierInfo();
646 5598: SelectorLoc = ConsumeToken();
647 5598: return II;
648 : }
649 : }
650 :
651 : /// objc-for-collection-in: 'in'
652 : ///
653 56: bool Parser::isTokIdentifier_in() const {
654 : // FIXME: May have to do additional look-ahead to only allow for
655 : // valid tokens following an 'in'; such as an identifier, unary operators,
656 : // '[' etc.
657 : return (getLang().ObjC2 && Tok.is(tok::identifier) &&
56: branch 1 taken
0: branch 2 not taken
56: branch 4 taken
0: branch 5 not taken
56: branch 7 taken
0: branch 8 not taken
658 56: Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
659 : }
660 :
661 : /// ParseObjCTypeQualifierList - This routine parses the objective-c's type
662 : /// qualifier list and builds their bitmask representation in the input
663 : /// argument.
664 : ///
665 : /// objc-type-qualifiers:
666 : /// objc-type-qualifier
667 : /// objc-type-qualifiers objc-type-qualifier
668 : ///
669 4779: void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
670 47: while (1) {
2551: branch 1 taken
2228: branch 2 taken
671 4779: if (Tok.isNot(tok::identifier))
672 2228: return;
673 :
674 2551: const IdentifierInfo *II = Tok.getIdentifierInfo();
15207: branch 0 taken
2504: branch 1 taken
675 17711: for (unsigned i = 0; i != objc_NumQuals; ++i) {
47: branch 0 taken
15160: branch 1 taken
676 15207: if (II != ObjCTypeQuals[i])
677 15160: continue;
678 :
679 : ObjCDeclSpec::ObjCDeclQualifier Qual;
0: branch 0 not taken
2: branch 1 taken
4: branch 2 taken
2: branch 3 taken
30: branch 4 taken
7: branch 5 taken
2: branch 6 taken
680 47: switch (i) {
681 0: default: assert(0 && "Unknown decl qualifier");
682 2: case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
683 4: case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
684 2: case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
685 30: case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
686 7: case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
687 2: case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
688 : }
689 47: DS.setObjCDeclQualifier(Qual);
690 47: ConsumeToken();
691 47: II = 0;
692 47: break;
693 : }
694 :
695 : // If this wasn't a recognized qualifier, bail out.
47: branch 0 taken
2504: branch 1 taken
696 2551: if (II) return;
697 : }
698 : }
699 :
700 : /// objc-type-name:
701 : /// '(' objc-type-qualifiers[opt] type-name ')'
702 : /// '(' objc-type-qualifiers[opt] ')'
703 : ///
704 4732: Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
4732: branch 1 taken
0: branch 2 not taken
705 4732: assert(Tok.is(tok::l_paren) && "expected (");
706 :
707 4732: SourceLocation LParenLoc = ConsumeParen();
708 4732: SourceLocation TypeStartLoc = Tok.getLocation();
709 :
710 : // Parse type qualifiers, in, inout, etc.
711 4732: ParseObjCTypeQualifierList(DS);
712 :
713 4732: TypeTy *Ty = 0;
4724: branch 1 taken
8: branch 2 taken
714 4732: if (isTypeSpecifierQualifier()) {
715 4724: TypeResult TypeSpec = ParseTypeName();
4724: branch 1 taken
0: branch 2 not taken
716 4724: if (!TypeSpec.isInvalid())
717 4724: Ty = TypeSpec.get();
718 : }
719 :
4725: branch 1 taken
7: branch 2 taken
720 4732: if (Tok.is(tok::r_paren))
721 4725: ConsumeParen();
6: branch 2 taken
1: branch 3 taken
722 7: else if (Tok.getLocation() == TypeStartLoc) {
723 : // If we didn't eat any tokens, then this isn't a type.
724 6: Diag(Tok, diag::err_expected_type);
725 6: SkipUntil(tok::r_paren);
726 : } else {
727 : // Otherwise, we found *something*, but didn't get a ')' in the right
728 : // place. Emit an error then return what we have as the type.
729 1: MatchRHSPunctuation(tok::r_paren, LParenLoc);
730 : }
731 4732: return Ty;
732 : }
733 :
734 : /// objc-method-decl:
735 : /// objc-selector
736 : /// objc-keyword-selector objc-parmlist[opt]
737 : /// objc-type-name objc-selector
738 : /// objc-type-name objc-keyword-selector objc-parmlist[opt]
739 : ///
740 : /// objc-keyword-selector:
741 : /// objc-keyword-decl
742 : /// objc-keyword-selector objc-keyword-decl
743 : ///
744 : /// objc-keyword-decl:
745 : /// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
746 : /// objc-selector ':' objc-keyword-attributes[opt] identifier
747 : /// ':' objc-type-name objc-keyword-attributes[opt] identifier
748 : /// ':' objc-keyword-attributes[opt] identifier
749 : ///
750 : /// objc-parmlist:
751 : /// objc-parms objc-ellipsis[opt]
752 : ///
753 : /// objc-parms:
754 : /// objc-parms , parameter-declaration
755 : ///
756 : /// objc-ellipsis:
757 : /// , ...
758 : ///
759 : /// objc-keyword-attributes: [OBJC2]
760 : /// __attribute__((unused))
761 : ///
762 : Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
763 : tok::TokenKind mType,
764 : DeclPtrTy IDecl,
765 3128: tok::ObjCKeywordKind MethodImplKind) {
766 3128: ParsingDeclRAIIObject PD(*this);
767 :
768 : // Parse the return type if present.
769 3128: TypeTy *ReturnType = 0;
770 3128: ObjCDeclSpec DSRet;
2921: branch 1 taken
207: branch 2 taken
771 3128: if (Tok.is(tok::l_paren))
772 2921: ReturnType = ParseObjCTypeName(DSRet);
773 :
774 3128: SourceLocation selLoc;
775 3128: IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
776 :
777 : // An unnamed colon is valid.
4: branch 0 taken
3124: branch 1 taken
1: branch 3 taken
3: branch 4 taken
1: branch 5 taken
3127: branch 6 taken
778 3128: if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
779 : Diag(Tok, diag::err_expected_selector_for_method)
780 1: << SourceRange(mLoc, Tok.getLocation());
781 : // Skip until we get a ; or {}.
782 1: SkipUntil(tok::r_brace);
783 1: return DeclPtrTy();
784 : }
785 :
786 3127: llvm::SmallVector<Declarator, 8> CargNames;
1803: branch 1 taken
1324: branch 2 taken
787 3127: if (Tok.isNot(tok::colon)) {
788 : // If attributes exist after the method, parse them.
789 1803: AttributeList *MethodAttrs = 0;
1803: branch 1 taken
0: branch 2 not taken
34: branch 4 taken
1769: branch 5 taken
34: branch 6 taken
1769: branch 7 taken
790 1803: if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
791 34: MethodAttrs = ParseGNUAttributes();
792 :
793 1803: Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
794 : DeclPtrTy Result
795 : = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
796 : mType, IDecl, DSRet, ReturnType, Sel,
797 : 0, CargNames, MethodAttrs,
798 1803: MethodImplKind);
799 1803: PD.complete(Result);
800 1803: return Result;
801 : }
802 :
803 1324: llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
804 1324: llvm::SmallVector<Action::ObjCArgInfo, 12> ArgInfos;
805 :
806 508: while (1) {
807 1832: Action::ObjCArgInfo ArgInfo;
808 :
809 : // Each iteration parses a single keyword argument.
0: branch 1 not taken
1832: branch 2 taken
810 1832: if (Tok.isNot(tok::colon)) {
811 0: Diag(Tok, diag::err_expected_colon);
812 0: break;
813 : }
814 1832: ConsumeToken(); // Eat the ':'.
815 :
816 1832: ArgInfo.Type = 0;
1811: branch 1 taken
21: branch 2 taken
817 1832: if (Tok.is(tok::l_paren)) // Parse the argument type if present.
818 1811: ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec);
819 :
820 : // If attributes exist before the argument name, parse them.
821 1832: ArgInfo.ArgAttrs = 0;
1832: branch 1 taken
0: branch 2 not taken
5: branch 4 taken
1827: branch 5 taken
5: branch 6 taken
1827: branch 7 taken
822 1832: if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
823 5: ArgInfo.ArgAttrs = ParseGNUAttributes();
824 :
1: branch 1 taken
1831: branch 2 taken
825 1832: if (Tok.isNot(tok::identifier)) {
826 1: Diag(Tok, diag::err_expected_ident); // missing argument name.
827 1: break;
828 : }
829 :
830 1831: ArgInfo.Name = Tok.getIdentifierInfo();
831 1831: ArgInfo.NameLoc = Tok.getLocation();
832 1831: ConsumeToken(); // Eat the identifier.
833 :
834 1831: ArgInfos.push_back(ArgInfo);
835 1831: KeyIdents.push_back(SelIdent);
836 :
837 : // Check for another keyword selector.
838 1831: SourceLocation Loc;
839 1831: SelIdent = ParseObjCSelectorPiece(Loc);
1368: branch 0 taken
463: branch 1 taken
1323: branch 3 taken
45: branch 4 taken
1323: branch 5 taken
508: branch 6 taken
840 1831: if (!SelIdent && Tok.isNot(tok::colon))
841 1323: break;
842 : // We have a selector or a colon, continue parsing.
843 : }
844 :
845 1324: bool isVariadic = false;
846 :
847 : // Parse the (optional) parameter list.
98: branch 3 taken
1228: branch 4 taken
848 1326: while (Tok.is(tok::comma)) {
849 98: ConsumeToken();
96: branch 1 taken
2: branch 2 taken
850 98: if (Tok.is(tok::ellipsis)) {
851 96: isVariadic = true;
852 96: ConsumeToken();
853 96: break;
854 : }
855 2: DeclSpec DS;
856 2: ParseDeclarationSpecifiers(DS);
857 : // Parse the declarator.
858 2: Declarator ParmDecl(DS, Declarator::PrototypeContext);
859 2: ParseDeclarator(ParmDecl);
860 2: CargNames.push_back(ParmDecl);
861 : }
862 :
863 : // FIXME: Add support for optional parmameter list...
864 : // If attributes exist after the method, parse them.
865 1324: AttributeList *MethodAttrs = 0;
1324: branch 1 taken
0: branch 2 not taken
21: branch 4 taken
1303: branch 5 taken
21: branch 6 taken
1303: branch 7 taken
866 1324: if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
867 21: MethodAttrs = ParseGNUAttributes();
868 :
1: branch 1 taken
1323: branch 2 taken
869 1324: if (KeyIdents.size() == 0)
870 1: return DeclPtrTy();
871 : Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
872 1323: &KeyIdents[0]);
873 : DeclPtrTy Result
874 : = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
875 : mType, IDecl, DSRet, ReturnType, Sel,
876 : &ArgInfos[0], CargNames, MethodAttrs,
877 1323: MethodImplKind, isVariadic);
878 1323: PD.complete(Result);
879 1323: return Result;
880 : }
881 :
882 : /// objc-protocol-refs:
883 : /// '<' identifier-list '>'
884 : ///
885 : bool Parser::
886 : ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
887 : llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs,
888 : bool WarnOnDeclarations,
889 862: SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
862: branch 1 taken
0: branch 2 not taken
890 862: assert(Tok.is(tok::less) && "expected <");
891 :
892 862: LAngleLoc = ConsumeToken(); // the "<"
893 :
894 862: llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
895 :
896 369: while (1) {
2: branch 1 taken
1229: branch 2 taken
897 1231: if (Tok.is(tok::code_completion)) {
898 : Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
899 2: ProtocolIdents.size());
900 2: ConsumeToken();
901 : }
902 :
2: branch 1 taken
1229: branch 2 taken
903 1231: if (Tok.isNot(tok::identifier)) {
904 2: Diag(Tok, diag::err_expected_ident);
905 2: SkipUntil(tok::greater);
906 2: return true;
907 : }
908 : ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
909 1229: Tok.getLocation()));
910 1229: ProtocolLocs.push_back(Tok.getLocation());
911 1229: ConsumeToken();
912 :
369: branch 1 taken
860: branch 2 taken
913 1229: if (Tok.isNot(tok::comma))
914 860: break;
915 369: ConsumeToken();
916 : }
917 :
918 : // Consume the '>'.
0: branch 1 not taken
860: branch 2 taken
919 860: if (Tok.isNot(tok::greater)) {
920 0: Diag(Tok, diag::err_expected_greater);
921 0: return true;
922 : }
923 :
924 860: EndLoc = ConsumeAnyToken();
925 :
926 : // Convert the list of protocols identifiers into a list of protocol decls.
927 : Actions.FindProtocolDeclaration(WarnOnDeclarations,
928 : &ProtocolIdents[0], ProtocolIdents.size(),
929 860: Protocols);
930 860: return false;
931 : }
932 :
933 : /// objc-class-instance-variables:
934 : /// '{' objc-instance-variable-decl-list[opt] '}'
935 : ///
936 : /// objc-instance-variable-decl-list:
937 : /// objc-visibility-spec
938 : /// objc-instance-variable-decl ';'
939 : /// ';'
940 : /// objc-instance-variable-decl-list objc-visibility-spec
941 : /// objc-instance-variable-decl-list objc-instance-variable-decl ';'
942 : /// objc-instance-variable-decl-list ';'
943 : ///
944 : /// objc-visibility-spec:
945 : /// @private
946 : /// @protected
947 : /// @public
948 : /// @package [OBJC2]
949 : ///
950 : /// objc-instance-variable-decl:
951 : /// struct-declaration
952 : ///
953 : void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
954 766: SourceLocation atLoc) {
766: branch 1 taken
0: branch 2 not taken
955 766: assert(Tok.is(tok::l_brace) && "expected {");
956 766: llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls;
957 :
958 766: ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
959 :
960 766: SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
961 :
962 766: tok::ObjCKeywordKind visibility = tok::objc_protected;
963 : // While we still have something to read, read the instance variables.
759: branch 1 taken
764: branch 2 taken
757: branch 4 taken
2: branch 5 taken
757: branch 6 taken
766: branch 7 taken
964 2289: while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
965 : // Each iteration of this loop reads one objc-instance-variable-decl.
966 :
967 : // Check for extraneous top-level semicolon.
0: branch 1 not taken
757: branch 2 taken
968 757: if (Tok.is(tok::semi)) {
969 : Diag(Tok, diag::ext_extra_struct_semi)
970 0: << CodeModificationHint::CreateRemoval(Tok.getLocation());
971 0: ConsumeToken();
972 0: continue;
973 : }
974 :
975 : // Set the default visibility to private.
79: branch 1 taken
678: branch 2 taken
976 757: if (Tok.is(tok::at)) { // parse objc-visibility-spec
977 79: ConsumeToken(); // eat the @ sign
978 :
1: branch 1 taken
78: branch 2 taken
979 79: if (Tok.is(tok::code_completion)) {
980 1: Actions.CodeCompleteObjCAtVisibility(CurScope);
981 1: ConsumeToken();
982 : }
983 :
78: branch 1 taken
1: branch 2 taken
984 79: switch (Tok.getObjCKeywordID()) {
985 : case tok::objc_private:
986 : case tok::objc_public:
987 : case tok::objc_protected:
988 : case tok::objc_package:
989 78: visibility = Tok.getObjCKeywordID();
990 78: ConsumeToken();
991 78: continue;
992 : default:
993 1: Diag(Tok, diag::err_objc_illegal_visibility_spec);
994 1: continue;
995 : }
996 : }
997 :
1: branch 1 taken
677: branch 2 taken
998 678: if (Tok.is(tok::code_completion)) {
999 : Actions.CodeCompleteOrdinaryName(CurScope,
1000 1: Action::CCC_ObjCInstanceVariableList);
1001 1: ConsumeToken();
1002 : }
1003 :
0: branch 1 not taken
0: branch 2 not taken
0: branch 5 not taken
678: branch 6 taken
0: branch 9 not taken
0: branch 10 not taken
1004 678: struct ObjCIvarCallback : FieldCallback {
1005 : Parser &P;
1006 : DeclPtrTy IDecl;
1007 : tok::ObjCKeywordKind visibility;
1008 : llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls;
1009 :
1010 : ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V,
1011 678: llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls) :
1012 678: P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
1013 678: }
1014 :
1015 690: DeclPtrTy invoke(FieldDeclarator &FD) {
1016 : // Install the declarator into the interface decl.
1017 : DeclPtrTy Field
1018 : = P.Actions.ActOnIvar(P.CurScope,
1019 : FD.D.getDeclSpec().getSourceRange().getBegin(),
1020 690: IDecl, FD.D, FD.BitfieldSize, visibility);
1021 690: AllIvarDecls.push_back(Field);
1022 : return Field;
1023 : }
1024 678: } Callback(*this, interfaceDecl, visibility, AllIvarDecls);
1025 :
1026 : // Parse all the comma separated declarators.
1027 678: DeclSpec DS;
1028 678: ParseStructDeclaration(DS, Callback);
1029 :
676: branch 1 taken
2: branch 2 taken
1030 678: if (Tok.is(tok::semi)) {
1031 676: ConsumeToken();
1032 : } else {
1033 2: Diag(Tok, diag::err_expected_semi_decl_list);
1034 : // Skip to end of block or statement
1035 2: SkipUntil(tok::r_brace, true, true);
1036 : }
1037 678: }
1038 766: SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
1039 : // Call ActOnFields() even if we don't have any decls. This is useful
1040 : // for code rewriting tools that need to be aware of the empty list.
1041 : Actions.ActOnFields(CurScope, atLoc, interfaceDecl,
1042 : AllIvarDecls.data(), AllIvarDecls.size(),
1043 766: LBraceLoc, RBraceLoc, 0);
1044 766: return;
1045 : }
1046 :
1047 : /// objc-protocol-declaration:
1048 : /// objc-protocol-definition
1049 : /// objc-protocol-forward-reference
1050 : ///
1051 : /// objc-protocol-definition:
1052 : /// @protocol identifier
1053 : /// objc-protocol-refs[opt]
1054 : /// objc-interface-decl-list
1055 : /// @end
1056 : ///
1057 : /// objc-protocol-forward-reference:
1058 : /// @protocol identifier-list ';'
1059 : ///
1060 : /// "@protocol identifier ;" should be resolved as "@protocol
1061 : /// identifier-list ;": objc-interface-decl-list may not start with a
1062 : /// semicolon in the first alternative if objc-protocol-refs are omitted.
1063 : Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
1064 735: AttributeList *attrList) {
1065 : assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
735: branch 1 taken
0: branch 2 not taken
1066 735: "ParseObjCAtProtocolDeclaration(): Expected @protocol");
1067 735: ConsumeToken(); // the "protocol" identifier
1068 :
1: branch 1 taken
734: branch 2 taken
1069 735: if (Tok.is(tok::code_completion)) {
1070 1: Actions.CodeCompleteObjCProtocolDecl(CurScope);
1071 1: ConsumeToken();
1072 : }
1073 :
1: branch 1 taken
734: branch 2 taken
1074 735: if (Tok.isNot(tok::identifier)) {
1075 1: Diag(Tok, diag::err_expected_ident); // missing protocol name.
1076 1: return DeclPtrTy();
1077 : }
1078 : // Save the protocol name, then consume it.
1079 734: IdentifierInfo *protocolName = Tok.getIdentifierInfo();
1080 734: SourceLocation nameLoc = ConsumeToken();
1081 :
66: branch 1 taken
668: branch 2 taken
1082 734: if (Tok.is(tok::semi)) { // forward declaration of one protocol.
1083 66: IdentifierLocPair ProtoInfo(protocolName, nameLoc);
1084 66: ConsumeToken();
1085 : return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
1086 66: attrList);
1087 : }
1088 :
7: branch 1 taken
661: branch 2 taken
1089 668: if (Tok.is(tok::comma)) { // list of forward declarations.
1090 7: llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
1091 7: ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
1092 :
1093 : // Parse the list of forward declarations.
1094 5: while (1) {
1095 12: ConsumeToken(); // the ','
0: branch 1 not taken
12: branch 2 taken
1096 12: if (Tok.isNot(tok::identifier)) {
1097 0: Diag(Tok, diag::err_expected_ident);
1098 0: SkipUntil(tok::semi);
1099 0: return DeclPtrTy();
1100 : }
1101 : ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
1102 12: Tok.getLocation()));
1103 12: ConsumeToken(); // the identifier
1104 :
5: branch 1 taken
7: branch 2 taken
1105 12: if (Tok.isNot(tok::comma))
1106 7: break;
1107 : }
1108 : // Consume the ';'.
0: branch 1 not taken
7: branch 2 taken
1109 7: if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
1110 0: return DeclPtrTy();
1111 :
1112 : return Actions.ActOnForwardProtocolDeclaration(AtLoc,
1113 : &ProtocolRefs[0],
1114 : ProtocolRefs.size(),
1115 7: attrList);
1116 : }
1117 :
1118 : // Last, and definitely not least, parse a protocol declaration.
1119 661: SourceLocation LAngleLoc, EndProtoLoc;
1120 :
1121 661: llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
1122 661: llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
85: branch 1 taken
576: branch 2 taken
0: branch 4 not taken
85: branch 5 taken
0: branch 6 not taken
661: branch 7 taken
1123 661: if (Tok.is(tok::less) &&
1124 : ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
1125 : LAngleLoc, EndProtoLoc))
1126 0: return DeclPtrTy();
1127 :
1128 : DeclPtrTy ProtoType =
1129 : Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
1130 : ProtocolRefs.data(),
1131 : ProtocolRefs.size(),
1132 : ProtocolLocs.data(),
1133 661: EndProtoLoc, attrList);
1134 661: ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
1135 661: return ProtoType;
1136 : }
1137 :
1138 : /// objc-implementation:
1139 : /// objc-class-implementation-prologue
1140 : /// objc-category-implementation-prologue
1141 : ///
1142 : /// objc-class-implementation-prologue:
1143 : /// @implementation identifier objc-superclass[opt]
1144 : /// objc-class-instance-variables[opt]
1145 : ///
1146 : /// objc-category-implementation-prologue:
1147 : /// @implementation identifier ( identifier )
1148 : Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
1149 652: SourceLocation atLoc) {
1150 : assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
652: branch 1 taken
0: branch 2 not taken
1151 652: "ParseObjCAtImplementationDeclaration(): Expected @implementation");
1152 652: ConsumeToken(); // the "implementation" identifier
1153 :
1154 : // Code completion after '@implementation'.
2: branch 1 taken
650: branch 2 taken
1155 652: if (Tok.is(tok::code_completion)) {
1156 2: Actions.CodeCompleteObjCImplementationDecl(CurScope);
1157 2: ConsumeToken();
1158 : }
1159 :
2: branch 1 taken
650: branch 2 taken
1160 652: if (Tok.isNot(tok::identifier)) {
1161 2: Diag(Tok, diag::err_expected_ident); // missing class or category name.
1162 2: return DeclPtrTy();
1163 : }
1164 : // We have a class or category name - consume it.
1165 650: IdentifierInfo *nameId = Tok.getIdentifierInfo();
1166 650: SourceLocation nameLoc = ConsumeToken(); // consume class or category name
1167 :
73: branch 1 taken
577: branch 2 taken
1168 650: if (Tok.is(tok::l_paren)) {
1169 : // we have a category implementation.
1170 73: SourceLocation lparenLoc = ConsumeParen();
1171 73: SourceLocation categoryLoc, rparenLoc;
1172 73: IdentifierInfo *categoryId = 0;
1173 :
3: branch 1 taken
70: branch 2 taken
1174 73: if (Tok.is(tok::code_completion)) {
1175 3: Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId);
1176 3: ConsumeToken();
1177 : }
1178 :
70: branch 1 taken
3: branch 2 taken
1179 73: if (Tok.is(tok::identifier)) {
1180 70: categoryId = Tok.getIdentifierInfo();
1181 70: categoryLoc = ConsumeToken();
1182 : } else {
1183 3: Diag(Tok, diag::err_expected_ident); // missing category name.
1184 3: return DeclPtrTy();
1185 : }
0: branch 1 not taken
70: branch 2 taken
1186 70: if (Tok.isNot(tok::r_paren)) {
1187 0: Diag(Tok, diag::err_expected_rparen);
1188 0: SkipUntil(tok::r_paren, false); // don't stop at ';'
1189 0: return DeclPtrTy();
1190 : }
1191 70: rparenLoc = ConsumeParen();
1192 : DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation(
1193 : atLoc, nameId, nameLoc, categoryId,
1194 70: categoryLoc);
1195 70: ObjCImpDecl = ImplCatType;
1196 70: PendingObjCImpDecl.push_back(ObjCImpDecl);
1197 70: return DeclPtrTy();
1198 : }
1199 : // We have a class implementation
1200 577: SourceLocation superClassLoc;
1201 577: IdentifierInfo *superClassId = 0;
18: branch 1 taken
559: branch 2 taken
1202 577: if (Tok.is(tok::colon)) {
1203 : // We have a super class
1204 18: ConsumeToken();
0: branch 1 not taken
18: branch 2 taken
1205 18: if (Tok.isNot(tok::identifier)) {
1206 0: Diag(Tok, diag::err_expected_ident); // missing super class name.
1207 0: return DeclPtrTy();
1208 : }
1209 18: superClassId = Tok.getIdentifierInfo();
1210 18: superClassLoc = ConsumeToken(); // Consume super class name
1211 : }
1212 : DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation(
1213 : atLoc, nameId, nameLoc,
1214 577: superClassId, superClassLoc);
1215 :
14: branch 1 taken
563: branch 2 taken
1216 577: if (Tok.is(tok::l_brace)) // we have ivars
1217 14: ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc);
1218 577: ObjCImpDecl = ImplClsType;
1219 577: PendingObjCImpDecl.push_back(ObjCImpDecl);
1220 :
1221 577: return DeclPtrTy();
1222 : }
1223 :
1224 633: Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
1225 : assert(Tok.isObjCAtKeyword(tok::objc_end) &&
633: branch 1 taken
0: branch 2 not taken
1226 633: "ParseObjCAtEndDeclaration(): Expected @end");
1227 633: DeclPtrTy Result = ObjCImpDecl;
1228 633: ConsumeToken(); // the "end" identifier
626: branch 1 taken
7: branch 2 taken
1229 633: if (ObjCImpDecl) {
1230 626: Actions.ActOnAtEnd(atEnd, ObjCImpDecl);
1231 626: ObjCImpDecl = DeclPtrTy();
1232 626: PendingObjCImpDecl.pop_back();
1233 : }
1234 : else {
1235 : // missing @implementation
1236 7: Diag(atEnd.getBegin(), diag::warn_expected_implementation);
1237 : }
1238 : return Result;
1239 : }
1240 :
1241 2251: Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
2236: branch 1 taken
15: branch 2 taken
1242 2251: if (PendingObjCImpDecl.empty())
1243 2236: return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
1244 15: DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
1245 15: Actions.ActOnAtEnd(SourceRange(), ImpDecl);
1246 15: return Actions.ConvertDeclToDeclGroup(ImpDecl);
1247 : }
1248 :
1249 : /// compatibility-alias-decl:
1250 : /// @compatibility_alias alias-name class-name ';'
1251 : ///
1252 10: Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
1253 : assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
10: branch 1 taken
0: branch 2 not taken
1254 10: "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
1255 10: ConsumeToken(); // consume compatibility_alias
0: branch 1 not taken
10: branch 2 taken
1256 10: if (Tok.isNot(tok::identifier)) {
1257 0: Diag(Tok, diag::err_expected_ident);
1258 0: return DeclPtrTy();
1259 : }
1260 10: IdentifierInfo *aliasId = Tok.getIdentifierInfo();
1261 10: SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
0: branch 1 not taken
10: branch 2 taken
1262 10: if (Tok.isNot(tok::identifier)) {
1263 0: Diag(Tok, diag::err_expected_ident);
1264 0: return DeclPtrTy();
1265 : }
1266 10: IdentifierInfo *classId = Tok.getIdentifierInfo();
1267 10: SourceLocation classLoc = ConsumeToken(); // consume class-name;
0: branch 1 not taken
10: branch 2 taken
1268 10: if (Tok.isNot(tok::semi)) {
1269 0: Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias";
1270 0: return DeclPtrTy();
1271 : }
1272 : return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc,
1273 10: classId, classLoc);
1274 : }
1275 :
1276 : /// property-synthesis:
1277 : /// @synthesize property-ivar-list ';'
1278 : ///
1279 : /// property-ivar-list:
1280 : /// property-ivar
1281 : /// property-ivar-list ',' property-ivar
1282 : ///
1283 : /// property-ivar:
1284 : /// identifier
1285 : /// identifier '=' identifier
1286 : ///
1287 167: Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
1288 : assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
167: branch 1 taken
0: branch 2 not taken
1289 167: "ParseObjCPropertyDynamic(): Expected '@synthesize'");
1290 167: SourceLocation loc = ConsumeToken(); // consume synthesize
1291 :
1292 49: while (true) {
2: branch 1 taken
214: branch 2 taken
1293 216: if (Tok.is(tok::code_completion)) {
1294 2: Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
1295 2: ConsumeToken();
1296 : }
1297 :
3: branch 1 taken
213: branch 2 taken
1298 216: if (Tok.isNot(tok::identifier)) {
1299 3: Diag(Tok, diag::err_synthesized_property_name);
1300 3: SkipUntil(tok::semi);
1301 3: return DeclPtrTy();
1302 : }
1303 :
1304 213: IdentifierInfo *propertyIvar = 0;
1305 213: IdentifierInfo *propertyId = Tok.getIdentifierInfo();
1306 213: SourceLocation propertyLoc = ConsumeToken(); // consume property name
96: branch 1 taken
117: branch 2 taken
1307 213: if (Tok.is(tok::equal)) {
1308 : // property '=' ivar-name
1309 96: ConsumeToken(); // consume '='
1310 :
1: branch 1 taken
95: branch 2 taken
1311 96: if (Tok.is(tok::code_completion)) {
1312 : Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId,
1313 1: ObjCImpDecl);
1314 1: ConsumeToken();
1315 : }
1316 :
1: branch 1 taken
95: branch 2 taken
1317 96: if (Tok.isNot(tok::identifier)) {
1318 1: Diag(Tok, diag::err_expected_ident);
1319 1: break;
1320 : }
1321 95: propertyIvar = Tok.getIdentifierInfo();
1322 95: ConsumeToken(); // consume ivar-name
1323 : }
1324 : Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
1325 212: propertyId, propertyIvar);
163: branch 1 taken
49: branch 2 taken
1326 212: if (Tok.isNot(tok::comma))
1327 163: break;
1328 49: ConsumeToken(); // consume ','
1329 : }
1: branch 1 taken
163: branch 2 taken
1330 164: if (Tok.isNot(tok::semi)) {
1331 1: Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
1332 1: SkipUntil(tok::semi);
1333 : }
1334 : else
1335 163: ConsumeToken(); // consume ';'
1336 164: return DeclPtrTy();
1337 : }
1338 :
1339 : /// property-dynamic:
1340 : /// @dynamic property-list
1341 : ///
1342 : /// property-list:
1343 : /// identifier
1344 : /// property-list ',' identifier
1345 : ///
1346 58: Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
1347 : assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
58: branch 1 taken
0: branch 2 not taken
1348 58: "ParseObjCPropertyDynamic(): Expected '@dynamic'");
1349 58: SourceLocation loc = ConsumeToken(); // consume dynamic
1350 26: while (true) {
1: branch 1 taken
83: branch 2 taken
1351 84: if (Tok.is(tok::code_completion)) {
1352 1: Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
1353 1: ConsumeToken();
1354 : }
1355 :
1: branch 1 taken
83: branch 2 taken
1356 84: if (Tok.isNot(tok::identifier)) {
1357 1: Diag(Tok, diag::err_expected_ident);
1358 1: SkipUntil(tok::semi);
1359 1: return DeclPtrTy();
1360 : }
1361 :
1362 83: IdentifierInfo *propertyId = Tok.getIdentifierInfo();
1363 83: SourceLocation propertyLoc = ConsumeToken(); // consume property name
1364 : Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
1365 83: propertyId, 0);
1366 :
26: branch 1 taken
57: branch 2 taken
1367 83: if (Tok.isNot(tok::comma))
1368 57: break;
1369 26: ConsumeToken(); // consume ','
1370 : }
0: branch 1 not taken
57: branch 2 taken
1371 57: if (Tok.isNot(tok::semi))
1372 0: Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
1373 57: return DeclPtrTy();
1374 : }
1375 :
1376 : /// objc-throw-statement:
1377 : /// throw expression[opt];
1378 : ///
1379 34: Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
1380 34: OwningExprResult Res(Actions);
1381 34: ConsumeToken(); // consume throw
20: branch 1 taken
14: branch 2 taken
1382 34: if (Tok.isNot(tok::semi)) {
1383 20: Res = ParseExpression();
0: branch 1 not taken
20: branch 2 taken
1384 20: if (Res.isInvalid()) {
1385 0: SkipUntil(tok::semi);
1386 0: return StmtError();
1387 : }
1388 : }
1389 34: ConsumeToken(); // consume ';'
1390 34: return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
1391 : }
1392 :
1393 : /// objc-synchronized-statement:
1394 : /// @synchronized '(' expression ')' compound-statement
1395 : ///
1396 : Parser::OwningStmtResult
1397 25: Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
1398 25: ConsumeToken(); // consume synchronized
0: branch 1 not taken
25: branch 2 taken
1399 25: if (Tok.isNot(tok::l_paren)) {
1400 0: Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
1401 0: return StmtError();
1402 : }
1403 25: ConsumeParen(); // '('
1404 25: OwningExprResult Res(ParseExpression());
1: branch 1 taken
24: branch 2 taken
1405 25: if (Res.isInvalid()) {
1406 1: SkipUntil(tok::semi);
1407 1: return StmtError();
1408 : }
0: branch 1 not taken
24: branch 2 taken
1409 24: if (Tok.isNot(tok::r_paren)) {
1410 0: Diag(Tok, diag::err_expected_lbrace);
1411 0: return StmtError();
1412 : }
1413 24: ConsumeParen(); // ')'
0: branch 1 not taken
24: branch 2 taken
1414 24: if (Tok.isNot(tok::l_brace)) {
1415 0: Diag(Tok, diag::err_expected_lbrace);
1416 0: return StmtError();
1417 : }
1418 : // Enter a scope to hold everything within the compound stmt. Compound
1419 : // statements can always hold declarations.
1420 24: ParseScope BodyScope(this, Scope::DeclScope);
1421 :
1422 24: OwningStmtResult SynchBody(ParseCompoundStatementBody());
1423 :
1424 24: BodyScope.Exit();
0: branch 1 not taken
24: branch 2 taken
1425 24: if (SynchBody.isInvalid())
1426 0: SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
1427 24: return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody));
1428 : }
1429 :
1430 : /// objc-try-catch-statement:
1431 : /// @try compound-statement objc-catch-list[opt]
1432 : /// @try compound-statement objc-catch-list[opt] @finally compound-statement
1433 : ///
1434 : /// objc-catch-list:
1435 : /// @catch ( parameter-declaration ) compound-statement
1436 : /// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
1437 : /// catch-parameter-declaration:
1438 : /// parameter-declaration
1439 : /// '...' [OBJC2]
1440 : ///
1441 54: Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
1442 54: bool catch_or_finally_seen = false;
1443 :
1444 54: ConsumeToken(); // consume try
0: branch 1 not taken
54: branch 2 taken
1445 54: if (Tok.isNot(tok::l_brace)) {
1446 0: Diag(Tok, diag::err_expected_lbrace);
1447 0: return StmtError();
1448 : }
1449 54: OwningStmtResult CatchStmts(Actions);
1450 54: OwningStmtResult FinallyStmt(Actions);
1451 54: ParseScope TryScope(this, Scope::DeclScope);
1452 54: OwningStmtResult TryBody(ParseCompoundStatementBody());
1453 54: TryScope.Exit();
0: branch 1 not taken
54: branch 2 taken
1454 54: if (TryBody.isInvalid())
1455 0: TryBody = Actions.ActOnNullStmt(Tok.getLocation());
1456 :
100: branch 1 taken
24: branch 2 taken
1457 178: while (Tok.is(tok::at)) {
1458 : // At this point, we need to lookahead to determine if this @ is the start
1459 : // of an @catch or @finally. We don't want to consume the @ token if this
1460 : // is an @try or @encode or something else.
1461 100: Token AfterAt = GetLookAheadToken(1);
30: branch 1 taken
70: branch 2 taken
7: branch 4 taken
23: branch 5 taken
7: branch 6 taken
93: branch 7 taken
1462 100: if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
1463 : !AfterAt.isObjCAtKeyword(tok::objc_finally))
1464 7: break;
1465 :
1466 93: SourceLocation AtCatchFinallyLoc = ConsumeToken();
70: branch 1 taken
23: branch 2 taken
1467 93: if (Tok.isObjCAtKeyword(tok::objc_catch)) {
1468 70: DeclPtrTy FirstPart;
1469 70: ConsumeToken(); // consume catch
70: branch 1 taken
0: branch 2 not taken
1470 70: if (Tok.is(tok::l_paren)) {
1471 70: ConsumeParen();
1472 70: ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
56: branch 1 taken
14: branch 2 taken
1473 70: if (Tok.isNot(tok::ellipsis)) {
1474 56: DeclSpec DS;
1475 56: ParseDeclarationSpecifiers(DS);
1476 : // For some odd reason, the name of the exception variable is
1477 : // optional. As a result, we need to use "PrototypeContext", because
1478 : // we must accept either 'declarator' or 'abstract-declarator' here.
1479 56: Declarator ParmDecl(DS, Declarator::PrototypeContext);
1480 56: ParseDeclarator(ParmDecl);
1481 :
1482 : // Inform the actions module about the parameter declarator, so it
1483 : // gets added to the current scope.
1484 : // FIXME. Probably can build a VarDecl and avoid setting DeclContext.
1485 56: FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
1486 56: Actions.ActOnObjCCatchParam(FirstPart);
1487 : } else
1488 14: ConsumeToken(); // consume '...'
1489 :
1490 70: SourceLocation RParenLoc;
1491 :
70: branch 1 taken
0: branch 2 not taken
1492 70: if (Tok.is(tok::r_paren))
1493 70: RParenLoc = ConsumeParen();
1494 : else // Skip over garbage, until we get to ')'. Eat the ')'.
1495 0: SkipUntil(tok::r_paren, true, false);
1496 :
1497 70: OwningStmtResult CatchBody(Actions, true);
70: branch 1 taken
0: branch 2 not taken
1498 70: if (Tok.is(tok::l_brace))
1499 70: CatchBody = ParseCompoundStatementBody();
1500 : else
1501 0: Diag(Tok, diag::err_expected_lbrace);
0: branch 1 not taken
70: branch 2 taken
1502 70: if (CatchBody.isInvalid())
1503 0: CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
1504 : CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
1505 : RParenLoc, FirstPart, move(CatchBody),
1506 70: move(CatchStmts));
1507 : } else {
1508 : Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
1509 0: << "@catch clause";
1510 0: return StmtError();
1511 : }
1512 70: catch_or_finally_seen = true;
1513 : } else {
23: branch 1 taken
0: branch 2 not taken
1514 23: assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
1515 23: ConsumeToken(); // consume finally
1516 23: ParseScope FinallyScope(this, Scope::DeclScope);
1517 :
1518 23: OwningStmtResult FinallyBody(Actions, true);
23: branch 1 taken
0: branch 2 not taken
1519 23: if (Tok.is(tok::l_brace))
1520 23: FinallyBody = ParseCompoundStatementBody();
1521 : else
1522 0: Diag(Tok, diag::err_expected_lbrace);
0: branch 1 not taken
23: branch 2 taken
1523 23: if (FinallyBody.isInvalid())
1524 0: FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
1525 : FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
1526 23: move(FinallyBody));
1527 23: catch_or_finally_seen = true;
1528 23: break;
1529 : }
1530 : }
6: branch 0 taken
48: branch 1 taken
1531 54: if (!catch_or_finally_seen) {
1532 6: Diag(atLoc, diag::err_missing_catch_finally);
1533 6: return StmtError();
1534 : }
1535 : return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
1536 48: move(FinallyStmt));
1537 : }
1538 :
1539 : /// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
1540 : ///
1541 924: Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
1542 924: DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
1543 :
1544 : PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions,
1545 : PP.getSourceManager(),
1546 924: "parsing Objective-C method");
1547 :
1548 : // parse optional ';'
2: branch 1 taken
922: branch 2 taken
1549 924: if (Tok.is(tok::semi)) {
1: branch 1 taken
1: branch 2 taken
1550 2: if (ObjCImpDecl) {
1551 : Diag(Tok, diag::warn_semicolon_before_method_body)
1552 1: << CodeModificationHint::CreateRemoval(Tok.getLocation());
1553 : }
1554 2: ConsumeToken();
1555 : }
1556 :
1557 : // We should have an opening brace now.
1: branch 1 taken
923: branch 2 taken
1558 924: if (Tok.isNot(tok::l_brace)) {
1559 1: Diag(Tok, diag::err_expected_method_body);
1560 :
1561 : // Skip over garbage, until we get to '{'. Don't eat the '{'.
1562 1: SkipUntil(tok::l_brace, true, true);
1563 :
1564 : // If we didn't find the '{', bail out.
1: branch 1 taken
0: branch 2 not taken
1565 1: if (Tok.isNot(tok::l_brace))
1566 1: return DeclPtrTy();
1567 : }
1568 923: SourceLocation BraceLoc = Tok.getLocation();
1569 :
1570 : // Enter a scope for the method body.
1571 923: ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
1572 :
1573 : // Tell the actions module that we have entered a method definition with the
1574 : // specified Declarator for the method.
1575 923: Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl);
1576 :
1577 923: OwningStmtResult FnBody(ParseCompoundStatementBody());
1578 :
1579 : // If the function body could not be parsed, make a bogus compoundstmt.
8: branch 1 taken
915: branch 2 taken
1580 923: if (FnBody.isInvalid())
1581 : FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
1582 8: MultiStmtArg(Actions), false);
1583 :
1584 : // TODO: Pass argument information.
1585 923: Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
1586 :
1587 : // Leave the function body scope.
1588 923: BodyScope.Exit();
1589 :
1590 923: return MDecl;
1591 : }
1592 :
1593 118: Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
1: branch 1 taken
117: branch 2 taken
1594 118: if (Tok.is(tok::code_completion)) {
1595 1: Actions.CodeCompleteObjCAtStatement(CurScope);
1596 1: ConsumeToken();
1597 1: return StmtError();
1598 : }
1599 :
54: branch 1 taken
63: branch 2 taken
1600 117: if (Tok.isObjCAtKeyword(tok::objc_try))
1601 54: return ParseObjCTryStmt(AtLoc);
1602 :
34: branch 1 taken
29: branch 2 taken
1603 63: if (Tok.isObjCAtKeyword(tok::objc_throw))
1604 34: return ParseObjCThrowStmt(AtLoc);
1605 :
25: branch 1 taken
4: branch 2 taken
1606 29: if (Tok.isObjCAtKeyword(tok::objc_synchronized))
1607 25: return ParseObjCSynchronizedStmt(AtLoc);
1608 :
1609 4: OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
0: branch 1 not taken
4: branch 2 taken
1610 4: if (Res.isInvalid()) {
1611 : // If the expression is invalid, skip ahead to the next semicolon. Not
1612 : // doing this opens us up to the possibility of infinite loops if
1613 : // ParseExpression does not consume any tokens.
1614 0: SkipUntil(tok::semi);
1615 0: return StmtError();
1616 : }
1617 :
1618 : // Otherwise, eat the semicolon.
1619 4: ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
1620 4: return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res));
1621 : }
1622 :
1623 322: Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
1: branch 1 taken
219: branch 2 taken
102: branch 3 taken
1624 322: switch (Tok.getKind()) {
1625 : case tok::code_completion:
1626 1: Actions.CodeCompleteObjCAtExpression(CurScope);
1627 1: ConsumeToken();
1628 1: return ExprError();
1629 :
1630 : case tok::string_literal: // primary-expression: string-literal
1631 : case tok::wide_string_literal:
1632 219: return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
1633 : default:
1: branch 1 taken
101: branch 2 taken
1634 102: if (Tok.getIdentifierInfo() == 0)
1635 1: return ExprError(Diag(AtLoc, diag::err_unexpected_at));
1636 :
30: branch 2 taken
22: branch 3 taken
49: branch 4 taken
0: branch 5 not taken
1637 101: switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
1638 : case tok::objc_encode:
1639 30: return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
1640 : case tok::objc_protocol:
1641 22: return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
1642 : case tok::objc_selector:
1643 49: return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
1644 : default:
1645 0: return ExprError(Diag(AtLoc, diag::err_unexpected_at));
1646 : }
1647 : }
1648 : }
1649 :
1650 : /// objc-message-expr:
1651 : /// '[' objc-receiver objc-message-args ']'
1652 : ///
1653 : /// objc-receiver:
1654 : /// expression
1655 : /// class-name
1656 : /// type-name
1657 1675: Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
1675: branch 1 taken
0: branch 2 not taken
1658 1675: assert(Tok.is(tok::l_square) && "'[' expected");
1659 1675: SourceLocation LBracLoc = ConsumeBracket(); // consume '['
1660 :
1661 : // Parse receiver
557: branch 1 taken
1118: branch 2 taken
1662 1675: if (isTokObjCMessageIdentifierReceiver()) {
1663 557: IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
113: branch 0 taken
444: branch 1 taken
112: branch 4 taken
1: branch 5 taken
556: branch 6 taken
1: branch 7 taken
1664 557: if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
1665 556: SourceLocation NameLoc = ConsumeToken();
1666 : return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
1667 556: ExprArg(Actions));
1668 : }
1669 : }
1670 :
1671 1119: OwningExprResult Res(ParseExpression());
11: branch 1 taken
1108: branch 2 taken
1672 1119: if (Res.isInvalid()) {
1673 11: SkipUntil(tok::r_square);
1674 11: return move(Res);
1675 : }
1676 :
1677 : return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
1678 1108: 0, move(Res));
1679 : }
1680 :
1681 : /// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
1682 : /// the rest of a message expression.
1683 : ///
1684 : /// objc-message-args:
1685 : /// objc-selector
1686 : /// objc-keywordarg-list
1687 : ///
1688 : /// objc-keywordarg-list:
1689 : /// objc-keywordarg
1690 : /// objc-keywordarg-list objc-keywordarg
1691 : ///
1692 : /// objc-keywordarg:
1693 : /// selector-name[opt] ':' objc-keywordexpr
1694 : ///
1695 : /// objc-keywordexpr:
1696 : /// nonempty-expr-list
1697 : ///
1698 : /// nonempty-expr-list:
1699 : /// assignment-expression
1700 : /// nonempty-expr-list , assignment-expression
1701 : ///
1702 : Parser::OwningExprResult
1703 : Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
1704 : SourceLocation NameLoc,
1705 : IdentifierInfo *ReceiverName,
1706 1690: ExprArg ReceiverExpr) {
10: branch 1 taken
1680: branch 2 taken
1707 1690: if (Tok.is(tok::code_completion)) {
5: branch 0 taken
5: branch 1 taken
1708 10: if (ReceiverName)
1709 : Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
1710 5: 0, 0);
1711 : else
1712 : Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
1713 5: 0, 0);
1714 10: ConsumeToken();
1715 : }
1716 :
1717 : // Parse objc-selector
1718 1690: SourceLocation Loc;
1719 1690: IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
1720 :
1721 1690: SourceLocation SelectorLoc = Loc;
1722 :
1723 1690: llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
1724 1690: ExprVector KeyExprs(Actions);
1725 :
413: branch 1 taken
1277: branch 2 taken
1726 1690: if (Tok.is(tok::colon)) {
268: branch 1 taken
0: branch 2 not taken
413: branch 3 taken
1727 681: while (1) {
1728 : // Each iteration parses a single keyword argument.
1729 681: KeyIdents.push_back(selIdent);
1730 :
0: branch 1 not taken
681: branch 2 taken
1731 681: if (Tok.isNot(tok::colon)) {
1732 0: Diag(Tok, diag::err_expected_colon);
1733 : // We must manually skip to a ']', otherwise the expression skipper will
1734 : // stop at the ']' when it skips to the ';'. We want it to skip beyond
1735 : // the enclosing expression.
1736 0: SkipUntil(tok::r_square);
1737 0: return ExprError();
1738 : }
1739 :
1740 681: ConsumeToken(); // Eat the ':'.
1741 : /// Parse the expression after ':'
1742 681: OwningExprResult Res(ParseAssignmentExpression());
0: branch 1 not taken
681: branch 2 taken
1743 681: if (Res.isInvalid()) {
1744 : // We must manually skip to a ']', otherwise the expression skipper will
1745 : // stop at the ']' when it skips to the ';'. We want it to skip beyond
1746 : // the enclosing expression.
1747 0: SkipUntil(tok::r_square);
1748 0: return move(Res);
1749 : }
1750 :
1751 : // We have a valid expression.
1752 681: KeyExprs.push_back(Res.release());
1753 :
1754 : // Code completion after each argument.
2: branch 1 taken
679: branch 2 taken
1755 681: if (Tok.is(tok::code_completion)) {
0: branch 0 not taken
2: branch 1 taken
1756 2: if (ReceiverName)
1757 : Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
1758 : KeyIdents.data(),
1759 0: KeyIdents.size());
1760 : else
1761 : Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
1762 : KeyIdents.data(),
1763 2: KeyIdents.size());
1764 2: ConsumeToken();
1765 : }
1766 :
1767 : // Check for another keyword selector.
1768 681: selIdent = ParseObjCSelectorPiece(Loc);
424: branch 0 taken
257: branch 1 taken
413: branch 3 taken
11: branch 4 taken
413: branch 5 taken
268: branch 6 taken
1769 681: if (!selIdent && Tok.isNot(tok::colon))
1770 : break;
1771 : // We have a selector or a colon, continue parsing.
1772 : }
1773 : // Parse the, optional, argument list, comma separated.
180: branch 1 taken
0: branch 2 not taken
180: branch 4 taken
413: branch 5 taken
1774 593: while (Tok.is(tok::comma)) {
1775 180: ConsumeToken(); // Eat the ','.
1776 : /// Parse the expression after ','
1777 180: OwningExprResult Res(ParseAssignmentExpression());
0: branch 1 not taken
180: branch 2 taken
1778 180: if (Res.isInvalid()) {
1779 : // We must manually skip to a ']', otherwise the expression skipper will
1780 : // stop at the ']' when it skips to the ';'. We want it to skip beyond
1781 : // the enclosing expression.
1782 0: SkipUntil(tok::r_square);
1783 0: return move(Res);
1784 : }
1785 :
1786 : // We have a valid expression.
1787 180: KeyExprs.push_back(Res.release());
1788 : }
10: branch 0 taken
1267: branch 1 taken
1789 1277: } else if (!selIdent) {
1790 10: Diag(Tok, diag::err_expected_ident); // missing selector name.
1791 :
1792 : // We must manually skip to a ']', otherwise the expression skipper will
1793 : // stop at the ']' when it skips to the ';'. We want it to skip beyond
1794 : // the enclosing expression.
1795 10: SkipUntil(tok::r_square);
1796 10: return ExprError();
1797 : }
1798 :
3: branch 1 taken
1677: branch 2 taken
1799 1680: if (Tok.isNot(tok::r_square)) {
1800 3: Diag(Tok, diag::err_expected_rsquare);
1801 : // We must manually skip to a ']', otherwise the expression skipper will
1802 : // stop at the ']' when it skips to the ';'. We want it to skip beyond
1803 : // the enclosing expression.
1804 3: SkipUntil(tok::r_square);
1805 3: return ExprError();
1806 : }
1807 :
1808 1677: SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
1809 :
1810 1677: unsigned nKeys = KeyIdents.size();
1267: branch 0 taken
410: branch 1 taken
1811 1677: if (nKeys == 0)
1812 1267: KeyIdents.push_back(selIdent);
1813 1677: Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
1814 :
1815 : // We've just parsed a keyword message.
554: branch 0 taken
1123: branch 1 taken
1816 1677: if (ReceiverName)
1817 : return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
1818 : LBracLoc, NameLoc, SelectorLoc,
1819 : RBracLoc,
1820 554: KeyExprs.take(), KeyExprs.size()));
1821 : return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
1822 : LBracLoc, SelectorLoc, RBracLoc,
1823 1123: KeyExprs.take(), KeyExprs.size()));
1824 : }
1825 :
1826 219: Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
1827 219: OwningExprResult Res(ParseStringLiteralExpression());
0: branch 1 not taken
219: branch 2 taken
1828 219: if (Res.isInvalid()) return move(Res);
1829 :
1830 : // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
1831 : // expressions. At this point, we know that the only valid thing that starts
1832 : // with '@' is an @"".
1833 219: llvm::SmallVector<SourceLocation, 4> AtLocs;
1834 219: ExprVector AtStrings(Actions);
1835 219: AtLocs.push_back(AtLoc);
1836 219: AtStrings.push_back(Res.release());
1837 :
8: branch 1 taken
0: branch 2 not taken
10: branch 4 taken
217: branch 5 taken
1838 8: while (Tok.is(tok::at)) {
1839 10: AtLocs.push_back(ConsumeToken()); // eat the @.
1840 :
1841 : // Invalid unless there is a string literal.
2: branch 1 taken
8: branch 2 taken
1842 10: if (!isTokenStringLiteral())
1843 2: return ExprError(Diag(Tok, diag::err_objc_concat_string));
1844 :
1845 8: OwningExprResult Lit(ParseStringLiteralExpression());
0: branch 1 not taken
8: branch 2 taken
1846 8: if (Lit.isInvalid())
1847 0: return move(Lit);
1848 :
1849 8: AtStrings.push_back(Lit.release());
1850 : }
1851 :
1852 : return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
1853 217: AtStrings.size()));
1854 : }
1855 :
1856 : /// objc-encode-expression:
1857 : /// @encode ( type-name )
1858 : Parser::OwningExprResult
1859 30: Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
30: branch 1 taken
0: branch 2 not taken
1860 30: assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
1861 :
1862 30: SourceLocation EncLoc = ConsumeToken();
1863 :
0: branch 1 not taken
30: branch 2 taken
1864 30: if (Tok.isNot(tok::l_paren))
1865 0: return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
1866 :
1867 30: SourceLocation LParenLoc = ConsumeParen();
1868 :
1869 30: TypeResult Ty = ParseTypeName();
1870 :
1871 30: SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
1872 :
0: branch 1 not taken
30: branch 2 taken
1873 30: if (Ty.isInvalid())
1874 0: return ExprError();
1875 :
1876 : return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
1877 30: Ty.get(), RParenLoc));
1878 : }
1879 :
1880 : /// objc-protocol-expression
1881 : /// @protocol ( protocol-name )
1882 : Parser::OwningExprResult
1883 22: Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
1884 22: SourceLocation ProtoLoc = ConsumeToken();
1885 :
0: branch 1 not taken
22: branch 2 taken
1886 22: if (Tok.isNot(tok::l_paren))
1887 0: return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
1888 :
1889 22: SourceLocation LParenLoc = ConsumeParen();
1890 :
0: branch 1 not taken
22: branch 2 taken
1891 22: if (Tok.isNot(tok::identifier))
1892 0: return ExprError(Diag(Tok, diag::err_expected_ident));
1893 :
1894 22: IdentifierInfo *protocolId = Tok.getIdentifierInfo();
1895 22: ConsumeToken();
1896 :
1897 22: SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
1898 :
1899 : return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
1900 22: LParenLoc, RParenLoc));
1901 : }
1902 :
1903 : /// objc-selector-expression
1904 : /// @selector '(' objc-keyword-selector ')'
1905 : Parser::OwningExprResult
1906 49: Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
1907 49: SourceLocation SelectorLoc = ConsumeToken();
1908 :
0: branch 1 not taken
49: branch 2 taken
1909 49: if (Tok.isNot(tok::l_paren))
1910 0: return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
1911 :
1912 49: llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
1913 49: SourceLocation LParenLoc = ConsumeParen();
1914 49: SourceLocation sLoc;
1915 49: IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
2: branch 0 taken
47: branch 1 taken
0: branch 3 not taken
2: branch 4 taken
0: branch 5 not taken
49: branch 6 taken
1916 49: if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name.
1917 0: return ExprError(Diag(Tok, diag::err_expected_ident));
1918 :
1919 49: KeyIdents.push_back(SelIdent);
1920 49: unsigned nColons = 0;
29: branch 1 taken
20: branch 2 taken
1921 49: if (Tok.isNot(tok::r_paren)) {
1922 38: while (1) {
0: branch 1 not taken
67: branch 2 taken
1923 67: if (Tok.isNot(tok::colon))
1924 0: return ExprError(Diag(Tok, diag::err_expected_colon));
1925 :
1926 67: nColons++;
1927 67: ConsumeToken(); // Eat the ':'.
38: branch 1 taken
29: branch 2 taken
1928 67: if (Tok.is(tok::r_paren))
1929 29: break;
1930 : // Check for another keyword selector.
1931 38: SourceLocation Loc;
1932 38: SelIdent = ParseObjCSelectorPiece(Loc);
1933 38: KeyIdents.push_back(SelIdent);
10: branch 0 taken
28: branch 1 taken
0: branch 3 not taken
10: branch 4 taken
0: branch 5 not taken
38: branch 6 taken
1934 38: if (!SelIdent && Tok.isNot(tok::colon))
1935 0: break;
1936 : }
1937 : }
1938 49: SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
1939 49: Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
1940 : return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
1941 49: LParenLoc, RParenLoc));
1942 0: }
Generated: 2010-02-10 01:31 by zcov