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