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