1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694 |
- //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the Objective-C portions of the Parser interface.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Parse/Parser.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/PrettyDeclStackTrace.h"
- #include "clang/Basic/CharInfo.h"
- #include "clang/Parse/ParseDiagnostic.h"
- #include "clang/Parse/RAIIObjectsForParser.h"
- #include "clang/Sema/DeclSpec.h"
- #include "clang/Sema/Scope.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringExtras.h"
- using namespace clang;
- /// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
- void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
- ParsedAttributes attrs(AttrFactory);
- if (Tok.is(tok::kw___attribute)) {
- if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
- Diag(Tok, diag::err_objc_postfix_attribute_hint)
- << (Kind == tok::objc_protocol);
- else
- Diag(Tok, diag::err_objc_postfix_attribute);
- ParseGNUAttributes(attrs);
- }
- }
- /// ParseObjCAtDirectives - Handle parts of the external-declaration production:
- /// external-declaration: [C99 6.9]
- /// [OBJC] objc-class-definition
- /// [OBJC] objc-class-declaration
- /// [OBJC] objc-alias-declaration
- /// [OBJC] objc-protocol-definition
- /// [OBJC] objc-method-definition
- /// [OBJC] '@' 'end'
- Parser::DeclGroupPtrTy
- Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
- SourceLocation AtLoc = ConsumeToken(); // the "@"
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- Decl *SingleDecl = nullptr;
- switch (Tok.getObjCKeywordID()) {
- case tok::objc_class:
- return ParseObjCAtClassDeclaration(AtLoc);
- case tok::objc_interface:
- SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, Attrs);
- break;
- case tok::objc_protocol:
- return ParseObjCAtProtocolDeclaration(AtLoc, Attrs);
- case tok::objc_implementation:
- return ParseObjCAtImplementationDeclaration(AtLoc, Attrs);
- case tok::objc_end:
- return ParseObjCAtEndDeclaration(AtLoc);
- case tok::objc_compatibility_alias:
- SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
- break;
- case tok::objc_synthesize:
- SingleDecl = ParseObjCPropertySynthesize(AtLoc);
- break;
- case tok::objc_dynamic:
- SingleDecl = ParseObjCPropertyDynamic(AtLoc);
- break;
- case tok::objc_import:
- if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {
- SingleDecl = ParseModuleImport(AtLoc);
- break;
- }
- Diag(AtLoc, diag::err_atimport);
- SkipUntil(tok::semi);
- return Actions.ConvertDeclToDeclGroup(nullptr);
- default:
- Diag(AtLoc, diag::err_unexpected_at);
- SkipUntil(tok::semi);
- SingleDecl = nullptr;
- break;
- }
- return Actions.ConvertDeclToDeclGroup(SingleDecl);
- }
- /// Class to handle popping type parameters when leaving the scope.
- class Parser::ObjCTypeParamListScope {
- Sema &Actions;
- Scope *S;
- ObjCTypeParamList *Params;
- public:
- ObjCTypeParamListScope(Sema &Actions, Scope *S)
- : Actions(Actions), S(S), Params(nullptr) {}
- ~ObjCTypeParamListScope() {
- leave();
- }
- void enter(ObjCTypeParamList *P) {
- assert(!Params);
- Params = P;
- }
- void leave() {
- if (Params)
- Actions.popObjCTypeParamList(S, Params);
- Params = nullptr;
- }
- };
- ///
- /// objc-class-declaration:
- /// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
- ///
- /// objc-class-forward-decl:
- /// identifier objc-type-parameter-list[opt]
- ///
- Parser::DeclGroupPtrTy
- Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
- ConsumeToken(); // the identifier "class"
- SmallVector<IdentifierInfo *, 8> ClassNames;
- SmallVector<SourceLocation, 8> ClassLocs;
- SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
- while (1) {
- MaybeSkipAttributes(tok::objc_class);
- if (expectIdentifier()) {
- SkipUntil(tok::semi);
- return Actions.ConvertDeclToDeclGroup(nullptr);
- }
- ClassNames.push_back(Tok.getIdentifierInfo());
- ClassLocs.push_back(Tok.getLocation());
- ConsumeToken();
- // Parse the optional objc-type-parameter-list.
- ObjCTypeParamList *TypeParams = nullptr;
- if (Tok.is(tok::less))
- TypeParams = parseObjCTypeParamList();
- ClassTypeParams.push_back(TypeParams);
- if (!TryConsumeToken(tok::comma))
- break;
- }
- // Consume the ';'.
- if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
- return Actions.ConvertDeclToDeclGroup(nullptr);
- return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
- ClassLocs.data(),
- ClassTypeParams,
- ClassNames.size());
- }
- void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
- {
- Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
- if (ock == Sema::OCK_None)
- return;
- Decl *Decl = Actions.getObjCDeclContext();
- if (CurParsedObjCImpl) {
- CurParsedObjCImpl->finish(AtLoc);
- } else {
- Actions.ActOnAtEnd(getCurScope(), AtLoc);
- }
- Diag(AtLoc, diag::err_objc_missing_end)
- << FixItHint::CreateInsertion(AtLoc, "@end\n");
- if (Decl)
- Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;
- }
- ///
- /// objc-interface:
- /// objc-class-interface-attributes[opt] objc-class-interface
- /// objc-category-interface
- ///
- /// objc-class-interface:
- /// '@' 'interface' identifier objc-type-parameter-list[opt]
- /// objc-superclass[opt] objc-protocol-refs[opt]
- /// objc-class-instance-variables[opt]
- /// objc-interface-decl-list
- /// @end
- ///
- /// objc-category-interface:
- /// '@' 'interface' identifier objc-type-parameter-list[opt]
- /// '(' identifier[opt] ')' objc-protocol-refs[opt]
- /// objc-interface-decl-list
- /// @end
- ///
- /// objc-superclass:
- /// ':' identifier objc-type-arguments[opt]
- ///
- /// objc-class-interface-attributes:
- /// __attribute__((visibility("default")))
- /// __attribute__((visibility("hidden")))
- /// __attribute__((deprecated))
- /// __attribute__((unavailable))
- /// __attribute__((objc_exception)) - used by NSException on 64-bit
- /// __attribute__((objc_root_class))
- ///
- Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
- ParsedAttributes &attrs) {
- assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
- "ParseObjCAtInterfaceDeclaration(): Expected @interface");
- CheckNestedObjCContexts(AtLoc);
- ConsumeToken(); // the "interface" identifier
- // Code completion after '@interface'.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- MaybeSkipAttributes(tok::objc_interface);
- if (expectIdentifier())
- return nullptr; // missing class or category name.
- // We have a class or category name - consume it.
- IdentifierInfo *nameId = Tok.getIdentifierInfo();
- SourceLocation nameLoc = ConsumeToken();
- // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
- // case, LAngleLoc will be valid and ProtocolIdents will capture the
- // protocol references (that have not yet been resolved).
- SourceLocation LAngleLoc, EndProtoLoc;
- SmallVector<IdentifierLocPair, 8> ProtocolIdents;
- ObjCTypeParamList *typeParameterList = nullptr;
- ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
- if (Tok.is(tok::less))
- typeParameterList = parseObjCTypeParamListOrProtocolRefs(
- typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);
- if (Tok.is(tok::l_paren) &&
- !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- SourceLocation categoryLoc;
- IdentifierInfo *categoryId = nullptr;
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
- cutOffParsing();
- return nullptr;
- }
- // For ObjC2, the category name is optional (not an error).
- if (Tok.is(tok::identifier)) {
- categoryId = Tok.getIdentifierInfo();
- categoryLoc = ConsumeToken();
- }
- else if (!getLangOpts().ObjC) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing category name.
- return nullptr;
- }
- T.consumeClose();
- if (T.getCloseLocation().isInvalid())
- return nullptr;
- // Next, we need to check for any protocol references.
- assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
- SmallVector<Decl *, 8> ProtocolRefs;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
- LAngleLoc, EndProtoLoc,
- /*consumeLastToken=*/true))
- return nullptr;
- Decl *CategoryType = Actions.ActOnStartCategoryInterface(
- AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
- ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
- EndProtoLoc, attrs);
- if (Tok.is(tok::l_brace))
- ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
- ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
- return CategoryType;
- }
- // Parse a class interface.
- IdentifierInfo *superClassId = nullptr;
- SourceLocation superClassLoc;
- SourceLocation typeArgsLAngleLoc;
- SmallVector<ParsedType, 4> typeArgs;
- SourceLocation typeArgsRAngleLoc;
- SmallVector<Decl *, 4> protocols;
- SmallVector<SourceLocation, 4> protocolLocs;
- if (Tok.is(tok::colon)) { // a super class is specified.
- ConsumeToken();
- // Code completion of superclass names.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
- cutOffParsing();
- return nullptr;
- }
- if (expectIdentifier())
- return nullptr; // missing super class name.
- superClassId = Tok.getIdentifierInfo();
- superClassLoc = ConsumeToken();
- // Type arguments for the superclass or protocol conformances.
- if (Tok.is(tok::less)) {
- parseObjCTypeArgsOrProtocolQualifiers(
- nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
- protocols, protocolLocs, EndProtoLoc,
- /*consumeLastToken=*/true,
- /*warnOnIncompleteProtocols=*/true);
- if (Tok.is(tok::eof))
- return nullptr;
- }
- }
- // Next, we need to check for any protocol references.
- if (LAngleLoc.isValid()) {
- if (!ProtocolIdents.empty()) {
- // We already parsed the protocols named when we thought we had a
- // type parameter list. Translate them into actual protocol references.
- for (const auto &pair : ProtocolIdents) {
- protocolLocs.push_back(pair.second);
- }
- Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
- /*ForObjCContainer=*/true,
- ProtocolIdents, protocols);
- }
- } else if (protocols.empty() && Tok.is(tok::less) &&
- ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
- LAngleLoc, EndProtoLoc,
- /*consumeLastToken=*/true)) {
- return nullptr;
- }
- if (Tok.isNot(tok::less))
- Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
- superClassId, superClassLoc);
- Decl *ClsType = Actions.ActOnStartClassInterface(
- getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
- superClassLoc, typeArgs,
- SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
- protocols.size(), protocolLocs.data(), EndProtoLoc, attrs);
- if (Tok.is(tok::l_brace))
- ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
- ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
- return ClsType;
- }
- /// Add an attribute for a context-sensitive type nullability to the given
- /// declarator.
- static void addContextSensitiveTypeNullability(Parser &P,
- Declarator &D,
- NullabilityKind nullability,
- SourceLocation nullabilityLoc,
- bool &addedToDeclSpec) {
- // Create the attribute.
- auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {
- return Pool.create(P.getNullabilityKeyword(nullability),
- SourceRange(nullabilityLoc), nullptr, SourceLocation(),
- nullptr, 0, ParsedAttr::AS_ContextSensitiveKeyword);
- };
- if (D.getNumTypeObjects() > 0) {
- // Add the attribute to the declarator chunk nearest the declarator.
- D.getTypeObject(0).getAttrs().addAtEnd(
- getNullabilityAttr(D.getAttributePool()));
- } else if (!addedToDeclSpec) {
- // Otherwise, just put it on the declaration specifiers (if one
- // isn't there already).
- D.getMutableDeclSpec().getAttributes().addAtEnd(
- getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));
- addedToDeclSpec = true;
- }
- }
- /// Parse an Objective-C type parameter list, if present, or capture
- /// the locations of the protocol identifiers for a list of protocol
- /// references.
- ///
- /// objc-type-parameter-list:
- /// '<' objc-type-parameter (',' objc-type-parameter)* '>'
- ///
- /// objc-type-parameter:
- /// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
- ///
- /// objc-type-parameter-bound:
- /// ':' type-name
- ///
- /// objc-type-parameter-variance:
- /// '__covariant'
- /// '__contravariant'
- ///
- /// \param lAngleLoc The location of the starting '<'.
- ///
- /// \param protocolIdents Will capture the list of identifiers, if the
- /// angle brackets contain a list of protocol references rather than a
- /// type parameter list.
- ///
- /// \param rAngleLoc The location of the ending '>'.
- ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
- ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,
- SmallVectorImpl<IdentifierLocPair> &protocolIdents,
- SourceLocation &rAngleLoc, bool mayBeProtocolList) {
- assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
- // Within the type parameter list, don't treat '>' as an operator.
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- // Local function to "flush" the protocol identifiers, turning them into
- // type parameters.
- SmallVector<Decl *, 4> typeParams;
- auto makeProtocolIdentsIntoTypeParameters = [&]() {
- unsigned index = 0;
- for (const auto &pair : protocolIdents) {
- DeclResult typeParam = Actions.actOnObjCTypeParam(
- getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
- index++, pair.first, pair.second, SourceLocation(), nullptr);
- if (typeParam.isUsable())
- typeParams.push_back(typeParam.get());
- }
- protocolIdents.clear();
- mayBeProtocolList = false;
- };
- bool invalid = false;
- lAngleLoc = ConsumeToken();
- do {
- // Parse the variance, if any.
- SourceLocation varianceLoc;
- ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
- if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
- variance = Tok.is(tok::kw___covariant)
- ? ObjCTypeParamVariance::Covariant
- : ObjCTypeParamVariance::Contravariant;
- varianceLoc = ConsumeToken();
- // Once we've seen a variance specific , we know this is not a
- // list of protocol references.
- if (mayBeProtocolList) {
- // Up until now, we have been queuing up parameters because they
- // might be protocol references. Turn them into parameters now.
- makeProtocolIdentsIntoTypeParameters();
- }
- }
- // Parse the identifier.
- if (!Tok.is(tok::identifier)) {
- // Code completion.
- if (Tok.is(tok::code_completion)) {
- // FIXME: If these aren't protocol references, we'll need different
- // completions.
- Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
- cutOffParsing();
- // FIXME: Better recovery here?.
- return nullptr;
- }
- Diag(Tok, diag::err_objc_expected_type_parameter);
- invalid = true;
- break;
- }
- IdentifierInfo *paramName = Tok.getIdentifierInfo();
- SourceLocation paramLoc = ConsumeToken();
- // If there is a bound, parse it.
- SourceLocation colonLoc;
- TypeResult boundType;
- if (TryConsumeToken(tok::colon, colonLoc)) {
- // Once we've seen a bound, we know this is not a list of protocol
- // references.
- if (mayBeProtocolList) {
- // Up until now, we have been queuing up parameters because they
- // might be protocol references. Turn them into parameters now.
- makeProtocolIdentsIntoTypeParameters();
- }
- // type-name
- boundType = ParseTypeName();
- if (boundType.isInvalid())
- invalid = true;
- } else if (mayBeProtocolList) {
- // If this could still be a protocol list, just capture the identifier.
- // We don't want to turn it into a parameter.
- protocolIdents.push_back(std::make_pair(paramName, paramLoc));
- continue;
- }
- // Create the type parameter.
- DeclResult typeParam = Actions.actOnObjCTypeParam(
- getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
- paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
- if (typeParam.isUsable())
- typeParams.push_back(typeParam.get());
- } while (TryConsumeToken(tok::comma));
- // Parse the '>'.
- if (invalid) {
- SkipUntil(tok::greater, tok::at, StopBeforeMatch);
- if (Tok.is(tok::greater))
- ConsumeToken();
- } else if (ParseGreaterThanInTemplateList(rAngleLoc,
- /*ConsumeLastToken=*/true,
- /*ObjCGenericList=*/true)) {
- Diag(lAngleLoc, diag::note_matching) << "'<'";
- SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
- tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
- tok::comma, tok::semi },
- StopBeforeMatch);
- if (Tok.is(tok::greater))
- ConsumeToken();
- }
- if (mayBeProtocolList) {
- // A type parameter list must be followed by either a ':' (indicating the
- // presence of a superclass) or a '(' (indicating that this is a category
- // or extension). This disambiguates between an objc-type-parameter-list
- // and a objc-protocol-refs.
- if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
- // Returning null indicates that we don't have a type parameter list.
- // The results the caller needs to handle the protocol references are
- // captured in the reference parameters already.
- return nullptr;
- }
- // We have a type parameter list that looks like a list of protocol
- // references. Turn that parameter list into type parameters.
- makeProtocolIdentsIntoTypeParameters();
- }
- // Form the type parameter list and enter its scope.
- ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
- getCurScope(),
- lAngleLoc,
- typeParams,
- rAngleLoc);
- Scope.enter(list);
- // Clear out the angle locations; they're used by the caller to indicate
- // whether there are any protocol references.
- lAngleLoc = SourceLocation();
- rAngleLoc = SourceLocation();
- return invalid ? nullptr : list;
- }
- /// Parse an objc-type-parameter-list.
- ObjCTypeParamList *Parser::parseObjCTypeParamList() {
- SourceLocation lAngleLoc;
- SmallVector<IdentifierLocPair, 1> protocolIdents;
- SourceLocation rAngleLoc;
- ObjCTypeParamListScope Scope(Actions, getCurScope());
- return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,
- rAngleLoc,
- /*mayBeProtocolList=*/false);
- }
- /// objc-interface-decl-list:
- /// empty
- /// objc-interface-decl-list objc-property-decl [OBJC2]
- /// objc-interface-decl-list objc-method-requirement [OBJC2]
- /// objc-interface-decl-list objc-method-proto ';'
- /// objc-interface-decl-list declaration
- /// objc-interface-decl-list ';'
- ///
- /// objc-method-requirement: [OBJC2]
- /// @required
- /// @optional
- ///
- void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
- Decl *CDecl) {
- SmallVector<Decl *, 32> allMethods;
- SmallVector<DeclGroupPtrTy, 8> allTUVariables;
- tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
- SourceRange AtEnd;
- while (1) {
- // If this is a method prototype, parse it.
- if (Tok.isOneOf(tok::minus, tok::plus)) {
- if (Decl *methodPrototype =
- ParseObjCMethodPrototype(MethodImplKind, false))
- allMethods.push_back(methodPrototype);
- // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
- // method definitions.
- if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
- // We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
- SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- }
- continue;
- }
- if (Tok.is(tok::l_paren)) {
- Diag(Tok, diag::err_expected_minus_or_plus);
- ParseObjCMethodDecl(Tok.getLocation(),
- tok::minus,
- MethodImplKind, false);
- continue;
- }
- // Ignore excess semicolons.
- if (Tok.is(tok::semi)) {
- // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,
- // to make -Wextra-semi diagnose them.
- ConsumeToken();
- continue;
- }
- // If we got to the end of the file, exit the loop.
- if (isEofOrEom())
- break;
- // Code completion within an Objective-C interface.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(getCurScope(),
- CurParsedObjCImpl? Sema::PCC_ObjCImplementation
- : Sema::PCC_ObjCInterface);
- return cutOffParsing();
- }
- // If we don't have an @ directive, parse it as a function definition.
- if (Tok.isNot(tok::at)) {
- // The code below does not consume '}'s because it is afraid of eating the
- // end of a namespace. Because of the way this code is structured, an
- // erroneous r_brace would cause an infinite loop if not handled here.
- if (Tok.is(tok::r_brace))
- break;
- ParsedAttributesWithRange attrs(AttrFactory);
- // Since we call ParseDeclarationOrFunctionDefinition() instead of
- // ParseExternalDeclaration() below (so that this doesn't parse nested
- // @interfaces), this needs to duplicate some code from the latter.
- if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
- SourceLocation DeclEnd;
- allTUVariables.push_back(
- ParseDeclaration(DeclaratorContext::FileContext, DeclEnd, attrs));
- continue;
- }
- allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
- continue;
- }
- // Otherwise, we have an @ directive, eat the @.
- SourceLocation AtLoc = ConsumeToken(); // the "@"
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope());
- return cutOffParsing();
- }
- tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
- if (DirectiveKind == tok::objc_end) { // @end -> terminate list
- AtEnd.setBegin(AtLoc);
- AtEnd.setEnd(Tok.getLocation());
- break;
- } else if (DirectiveKind == tok::objc_not_keyword) {
- Diag(Tok, diag::err_objc_unknown_at);
- SkipUntil(tok::semi);
- continue;
- }
- // Eat the identifier.
- ConsumeToken();
- switch (DirectiveKind) {
- default:
- // FIXME: If someone forgets an @end on a protocol, this loop will
- // continue to eat up tons of stuff and spew lots of nonsense errors. It
- // would probably be better to bail out if we saw an @class or @interface
- // or something like that.
- Diag(AtLoc, diag::err_objc_illegal_interface_qual);
- // Skip until we see an '@' or '}' or ';'.
- SkipUntil(tok::r_brace, tok::at, StopAtSemi);
- break;
- case tok::objc_implementation:
- case tok::objc_interface:
- Diag(AtLoc, diag::err_objc_missing_end)
- << FixItHint::CreateInsertion(AtLoc, "@end\n");
- Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
- << (int)Actions.getObjCContainerKind();
- ConsumeToken();
- break;
- case tok::objc_required:
- case tok::objc_optional:
- // This is only valid on protocols.
- if (contextKey != tok::objc_protocol)
- Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
- else
- MethodImplKind = DirectiveKind;
- break;
- case tok::objc_property:
- ObjCDeclSpec OCDS;
- SourceLocation LParenLoc;
- // Parse property attribute list, if any.
- if (Tok.is(tok::l_paren)) {
- LParenLoc = Tok.getLocation();
- ParseObjCPropertyAttribute(OCDS);
- }
- bool addedToDeclSpec = false;
- auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
- if (FD.D.getIdentifier() == nullptr) {
- Diag(AtLoc, diag::err_objc_property_requires_field_name)
- << FD.D.getSourceRange();
- return;
- }
- if (FD.BitfieldSize) {
- Diag(AtLoc, diag::err_objc_property_bitfield)
- << FD.D.getSourceRange();
- return;
- }
- // Map a nullability property attribute to a context-sensitive keyword
- // attribute.
- if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
- addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
- OCDS.getNullabilityLoc(),
- addedToDeclSpec);
- // Install the property declarator into interfaceDecl.
- IdentifierInfo *SelName =
- OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
- Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
- IdentifierInfo *SetterName = OCDS.getSetterName();
- Selector SetterSel;
- if (SetterName)
- SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
- else
- SetterSel = SelectorTable::constructSetterSelector(
- PP.getIdentifierTable(), PP.getSelectorTable(),
- FD.D.getIdentifier());
- Decl *Property = Actions.ActOnProperty(
- getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
- MethodImplKind);
- FD.complete(Property);
- };
- // Parse all the comma separated declarators.
- ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, ObjCPropertyCallback);
- ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
- break;
- }
- }
- // We break out of the big loop in two cases: when we see @end or when we see
- // EOF. In the former case, eat the @end. In the later case, emit an error.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope());
- return cutOffParsing();
- } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
- ConsumeToken(); // the "end" identifier
- } else {
- Diag(Tok, diag::err_objc_missing_end)
- << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
- Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
- << (int)Actions.getObjCContainerKind();
- AtEnd.setBegin(Tok.getLocation());
- AtEnd.setEnd(Tok.getLocation());
- }
- // Insert collected methods declarations into the @interface object.
- // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
- }
- /// Diagnose redundant or conflicting nullability information.
- static void diagnoseRedundantPropertyNullability(Parser &P,
- ObjCDeclSpec &DS,
- NullabilityKind nullability,
- SourceLocation nullabilityLoc){
- if (DS.getNullability() == nullability) {
- P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
- << DiagNullabilityKind(nullability, true)
- << SourceRange(DS.getNullabilityLoc());
- return;
- }
- P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
- << DiagNullabilityKind(nullability, true)
- << DiagNullabilityKind(DS.getNullability(), true)
- << SourceRange(DS.getNullabilityLoc());
- }
- /// Parse property attribute declarations.
- ///
- /// property-attr-decl: '(' property-attrlist ')'
- /// property-attrlist:
- /// property-attribute
- /// property-attrlist ',' property-attribute
- /// property-attribute:
- /// getter '=' identifier
- /// setter '=' identifier ':'
- /// readonly
- /// readwrite
- /// assign
- /// retain
- /// copy
- /// nonatomic
- /// atomic
- /// strong
- /// weak
- /// unsafe_unretained
- /// nonnull
- /// nullable
- /// null_unspecified
- /// null_resettable
- /// class
- ///
- void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
- assert(Tok.getKind() == tok::l_paren);
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- while (1) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
- return cutOffParsing();
- }
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- // If this is not an identifier at all, bail out early.
- if (!II) {
- T.consumeClose();
- return;
- }
- SourceLocation AttrName = ConsumeToken(); // consume last attribute name
- if (II->isStr("readonly"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
- else if (II->isStr("assign"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
- else if (II->isStr("unsafe_unretained"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
- else if (II->isStr("readwrite"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
- else if (II->isStr("retain"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
- else if (II->isStr("strong"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
- else if (II->isStr("copy"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
- else if (II->isStr("nonatomic"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
- else if (II->isStr("atomic"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
- else if (II->isStr("weak"))
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
- else if (II->isStr("getter") || II->isStr("setter")) {
- bool IsSetter = II->getNameStart()[0] == 's';
- // getter/setter require extra treatment.
- unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
- diag::err_objc_expected_equal_for_getter;
- if (ExpectAndConsume(tok::equal, DiagID)) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return;
- }
- if (Tok.is(tok::code_completion)) {
- if (IsSetter)
- Actions.CodeCompleteObjCPropertySetter(getCurScope());
- else
- Actions.CodeCompleteObjCPropertyGetter(getCurScope());
- return cutOffParsing();
- }
- SourceLocation SelLoc;
- IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
- if (!SelIdent) {
- Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
- << IsSetter;
- SkipUntil(tok::r_paren, StopAtSemi);
- return;
- }
- if (IsSetter) {
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
- DS.setSetterName(SelIdent, SelLoc);
- if (ExpectAndConsume(tok::colon,
- diag::err_expected_colon_after_setter_name)) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return;
- }
- } else {
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
- DS.setGetterName(SelIdent, SelLoc);
- }
- } else if (II->isStr("nonnull")) {
- if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
- diagnoseRedundantPropertyNullability(*this, DS,
- NullabilityKind::NonNull,
- Tok.getLocation());
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
- DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
- } else if (II->isStr("nullable")) {
- if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
- diagnoseRedundantPropertyNullability(*this, DS,
- NullabilityKind::Nullable,
- Tok.getLocation());
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
- DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
- } else if (II->isStr("null_unspecified")) {
- if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
- diagnoseRedundantPropertyNullability(*this, DS,
- NullabilityKind::Unspecified,
- Tok.getLocation());
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
- DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
- } else if (II->isStr("null_resettable")) {
- if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
- diagnoseRedundantPropertyNullability(*this, DS,
- NullabilityKind::Unspecified,
- Tok.getLocation());
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
- DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
- // Also set the null_resettable bit.
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
- } else if (II->isStr("class")) {
- DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class);
- } else {
- Diag(AttrName, diag::err_objc_expected_property_attr) << II;
- SkipUntil(tok::r_paren, StopAtSemi);
- return;
- }
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken();
- }
- T.consumeClose();
- }
- /// objc-method-proto:
- /// objc-instance-method objc-method-decl objc-method-attributes[opt]
- /// objc-class-method objc-method-decl objc-method-attributes[opt]
- ///
- /// objc-instance-method: '-'
- /// objc-class-method: '+'
- ///
- /// objc-method-attributes: [OBJC2]
- /// __attribute__((deprecated))
- ///
- Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
- bool MethodDefinition) {
- assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
- tok::TokenKind methodType = Tok.getKind();
- SourceLocation mLoc = ConsumeToken();
- Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
- MethodDefinition);
- // Since this rule is used for both method declarations and definitions,
- // the caller is (optionally) responsible for consuming the ';'.
- return MDecl;
- }
- /// objc-selector:
- /// identifier
- /// one of
- /// enum struct union if else while do for switch case default
- /// break continue return goto asm sizeof typeof __alignof
- /// unsigned long const short volatile signed restrict _Complex
- /// in out inout bycopy byref oneway int char float double void _Bool
- ///
- IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
- switch (Tok.getKind()) {
- default:
- return nullptr;
- case tok::colon:
- // Empty selector piece uses the location of the ':'.
- SelectorLoc = Tok.getLocation();
- return nullptr;
- case tok::ampamp:
- case tok::ampequal:
- case tok::amp:
- case tok::pipe:
- case tok::tilde:
- case tok::exclaim:
- case tok::exclaimequal:
- case tok::pipepipe:
- case tok::pipeequal:
- case tok::caret:
- case tok::caretequal: {
- std::string ThisTok(PP.getSpelling(Tok));
- if (isLetter(ThisTok[0])) {
- IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);
- Tok.setKind(tok::identifier);
- SelectorLoc = ConsumeToken();
- return II;
- }
- return nullptr;
- }
- case tok::identifier:
- case tok::kw_asm:
- case tok::kw_auto:
- case tok::kw_bool:
- case tok::kw_break:
- case tok::kw_case:
- case tok::kw_catch:
- case tok::kw_char:
- case tok::kw_class:
- case tok::kw_const:
- case tok::kw_const_cast:
- case tok::kw_continue:
- case tok::kw_default:
- case tok::kw_delete:
- case tok::kw_do:
- case tok::kw_double:
- case tok::kw_dynamic_cast:
- case tok::kw_else:
- case tok::kw_enum:
- case tok::kw_explicit:
- case tok::kw_export:
- case tok::kw_extern:
- case tok::kw_false:
- case tok::kw_float:
- case tok::kw_for:
- case tok::kw_friend:
- case tok::kw_goto:
- case tok::kw_if:
- case tok::kw_inline:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw_mutable:
- case tok::kw_namespace:
- case tok::kw_new:
- case tok::kw_operator:
- case tok::kw_private:
- case tok::kw_protected:
- case tok::kw_public:
- case tok::kw_register:
- case tok::kw_reinterpret_cast:
- case tok::kw_restrict:
- case tok::kw_return:
- case tok::kw_short:
- case tok::kw_signed:
- case tok::kw_sizeof:
- case tok::kw_static:
- case tok::kw_static_cast:
- case tok::kw_struct:
- case tok::kw_switch:
- case tok::kw_template:
- case tok::kw_this:
- case tok::kw_throw:
- case tok::kw_true:
- case tok::kw_try:
- case tok::kw_typedef:
- case tok::kw_typeid:
- case tok::kw_typename:
- case tok::kw_typeof:
- case tok::kw_union:
- case tok::kw_unsigned:
- case tok::kw_using:
- case tok::kw_virtual:
- case tok::kw_void:
- case tok::kw_volatile:
- case tok::kw_wchar_t:
- case tok::kw_while:
- case tok::kw__Bool:
- case tok::kw__Complex:
- case tok::kw___alignof:
- case tok::kw___auto_type:
- IdentifierInfo *II = Tok.getIdentifierInfo();
- SelectorLoc = ConsumeToken();
- return II;
- }
- }
- /// objc-for-collection-in: 'in'
- ///
- bool Parser::isTokIdentifier_in() const {
- // FIXME: May have to do additional look-ahead to only allow for
- // valid tokens following an 'in'; such as an identifier, unary operators,
- // '[' etc.
- return (getLangOpts().ObjC && Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
- }
- /// ParseObjCTypeQualifierList - This routine parses the objective-c's type
- /// qualifier list and builds their bitmask representation in the input
- /// argument.
- ///
- /// objc-type-qualifiers:
- /// objc-type-qualifier
- /// objc-type-qualifiers objc-type-qualifier
- ///
- /// objc-type-qualifier:
- /// 'in'
- /// 'out'
- /// 'inout'
- /// 'oneway'
- /// 'bycopy'
- /// 'byref'
- /// 'nonnull'
- /// 'nullable'
- /// 'null_unspecified'
- ///
- void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
- DeclaratorContext Context) {
- assert(Context == DeclaratorContext::ObjCParameterContext ||
- Context == DeclaratorContext::ObjCResultContext);
- while (1) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPassingType(getCurScope(), DS,
- Context == DeclaratorContext::ObjCParameterContext);
- return cutOffParsing();
- }
- if (Tok.isNot(tok::identifier))
- return;
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- for (unsigned i = 0; i != objc_NumQuals; ++i) {
- if (II != ObjCTypeQuals[i] ||
- NextToken().is(tok::less) ||
- NextToken().is(tok::coloncolon))
- continue;
- ObjCDeclSpec::ObjCDeclQualifier Qual;
- NullabilityKind Nullability;
- switch (i) {
- default: llvm_unreachable("Unknown decl qualifier");
- case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
- case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
- case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
- case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
- case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
- case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
- case objc_nonnull:
- Qual = ObjCDeclSpec::DQ_CSNullability;
- Nullability = NullabilityKind::NonNull;
- break;
- case objc_nullable:
- Qual = ObjCDeclSpec::DQ_CSNullability;
- Nullability = NullabilityKind::Nullable;
- break;
- case objc_null_unspecified:
- Qual = ObjCDeclSpec::DQ_CSNullability;
- Nullability = NullabilityKind::Unspecified;
- break;
- }
- // FIXME: Diagnose redundant specifiers.
- DS.setObjCDeclQualifier(Qual);
- if (Qual == ObjCDeclSpec::DQ_CSNullability)
- DS.setNullability(Tok.getLocation(), Nullability);
- ConsumeToken();
- II = nullptr;
- break;
- }
- // If this wasn't a recognized qualifier, bail out.
- if (II) return;
- }
- }
- /// Take all the decl attributes out of the given list and add
- /// them to the given attribute set.
- static void takeDeclAttributes(ParsedAttributesView &attrs,
- ParsedAttributesView &from) {
- for (auto &AL : llvm::reverse(from)) {
- if (!AL.isUsedAsTypeAttr()) {
- from.remove(&AL);
- attrs.addAtEnd(&AL);
- }
- }
- }
- /// takeDeclAttributes - Take all the decl attributes from the given
- /// declarator and add them to the given list.
- static void takeDeclAttributes(ParsedAttributes &attrs,
- Declarator &D) {
- // First, take ownership of all attributes.
- attrs.getPool().takeAllFrom(D.getAttributePool());
- attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
- // Now actually move the attributes over.
- takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
- takeDeclAttributes(attrs, D.getAttributes());
- for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
- takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
- }
- /// objc-type-name:
- /// '(' objc-type-qualifiers[opt] type-name ')'
- /// '(' objc-type-qualifiers[opt] ')'
- ///
- ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
- DeclaratorContext context,
- ParsedAttributes *paramAttrs) {
- assert(context == DeclaratorContext::ObjCParameterContext ||
- context == DeclaratorContext::ObjCResultContext);
- assert((paramAttrs != nullptr) ==
- (context == DeclaratorContext::ObjCParameterContext));
- assert(Tok.is(tok::l_paren) && "expected (");
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- ObjCDeclContextSwitch ObjCDC(*this);
- // Parse type qualifiers, in, inout, etc.
- ParseObjCTypeQualifierList(DS, context);
- SourceLocation TypeStartLoc = Tok.getLocation();
- ParsedType Ty;
- if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
- // Parse an abstract declarator.
- DeclSpec declSpec(AttrFactory);
- declSpec.setObjCQualifiers(&DS);
- DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
- if (context == DeclaratorContext::ObjCResultContext)
- dsContext = DeclSpecContext::DSC_objc_method_result;
- ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
- Declarator declarator(declSpec, context);
- ParseDeclarator(declarator);
- // If that's not invalid, extract a type.
- if (!declarator.isInvalidType()) {
- // Map a nullability specifier to a context-sensitive keyword attribute.
- bool addedToDeclSpec = false;
- if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
- addContextSensitiveTypeNullability(*this, declarator,
- DS.getNullability(),
- DS.getNullabilityLoc(),
- addedToDeclSpec);
- TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
- if (!type.isInvalid())
- Ty = type.get();
- // If we're parsing a parameter, steal all the decl attributes
- // and add them to the decl spec.
- if (context == DeclaratorContext::ObjCParameterContext)
- takeDeclAttributes(*paramAttrs, declarator);
- }
- }
- if (Tok.is(tok::r_paren))
- T.consumeClose();
- else if (Tok.getLocation() == TypeStartLoc) {
- // If we didn't eat any tokens, then this isn't a type.
- Diag(Tok, diag::err_expected_type);
- SkipUntil(tok::r_paren, StopAtSemi);
- } else {
- // Otherwise, we found *something*, but didn't get a ')' in the right
- // place. Emit an error then return what we have as the type.
- T.consumeClose();
- }
- return Ty;
- }
- /// objc-method-decl:
- /// objc-selector
- /// objc-keyword-selector objc-parmlist[opt]
- /// objc-type-name objc-selector
- /// objc-type-name objc-keyword-selector objc-parmlist[opt]
- ///
- /// objc-keyword-selector:
- /// objc-keyword-decl
- /// objc-keyword-selector objc-keyword-decl
- ///
- /// objc-keyword-decl:
- /// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
- /// objc-selector ':' objc-keyword-attributes[opt] identifier
- /// ':' objc-type-name objc-keyword-attributes[opt] identifier
- /// ':' objc-keyword-attributes[opt] identifier
- ///
- /// objc-parmlist:
- /// objc-parms objc-ellipsis[opt]
- ///
- /// objc-parms:
- /// objc-parms , parameter-declaration
- ///
- /// objc-ellipsis:
- /// , ...
- ///
- /// objc-keyword-attributes: [OBJC2]
- /// __attribute__((unused))
- ///
- Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
- tok::TokenKind mType,
- tok::ObjCKeywordKind MethodImplKind,
- bool MethodDefinition) {
- ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
- /*ReturnType=*/nullptr);
- cutOffParsing();
- return nullptr;
- }
- // Parse the return type if present.
- ParsedType ReturnType;
- ObjCDeclSpec DSRet;
- if (Tok.is(tok::l_paren))
- ReturnType = ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResultContext,
- nullptr);
- // If attributes exist before the method, parse them.
- ParsedAttributes methodAttrs(AttrFactory);
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
- ReturnType);
- cutOffParsing();
- return nullptr;
- }
- // Now parse the selector.
- SourceLocation selLoc;
- IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
- // An unnamed colon is valid.
- if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
- Diag(Tok, diag::err_expected_selector_for_method)
- << SourceRange(mLoc, Tok.getLocation());
- // Skip until we get a ; or @.
- SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
- return nullptr;
- }
- SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
- if (Tok.isNot(tok::colon)) {
- // If attributes exist after the method, parse them.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
- Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
- Decl *Result = Actions.ActOnMethodDeclaration(
- getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,
- selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
- MethodImplKind, false, MethodDefinition);
- PD.complete(Result);
- return Result;
- }
- SmallVector<IdentifierInfo *, 12> KeyIdents;
- SmallVector<SourceLocation, 12> KeyLocs;
- SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope | Scope::DeclScope);
- AttributePool allParamAttrs(AttrFactory);
- while (1) {
- ParsedAttributes paramAttrs(AttrFactory);
- Sema::ObjCArgInfo ArgInfo;
- // Each iteration parses a single keyword argument.
- if (ExpectAndConsume(tok::colon))
- break;
- ArgInfo.Type = nullptr;
- if (Tok.is(tok::l_paren)) // Parse the argument type if present.
- ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec,
- DeclaratorContext::ObjCParameterContext,
- ¶mAttrs);
- // If attributes exist before the argument name, parse them.
- // Regardless, collect all the attributes we've parsed so far.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(paramAttrs);
- MaybeParseCXX11Attributes(paramAttrs);
- ArgInfo.ArgAttrs = paramAttrs;
- // Code completion for the next piece of the selector.
- if (Tok.is(tok::code_completion)) {
- KeyIdents.push_back(SelIdent);
- Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
- mType == tok::minus,
- /*AtParameterName=*/true,
- ReturnType, KeyIdents);
- cutOffParsing();
- return nullptr;
- }
- if (expectIdentifier())
- break; // missing argument name.
- ArgInfo.Name = Tok.getIdentifierInfo();
- ArgInfo.NameLoc = Tok.getLocation();
- ConsumeToken(); // Eat the identifier.
- ArgInfos.push_back(ArgInfo);
- KeyIdents.push_back(SelIdent);
- KeyLocs.push_back(selLoc);
- // Make sure the attributes persist.
- allParamAttrs.takeAllFrom(paramAttrs.getPool());
- // Code completion for the next piece of the selector.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
- mType == tok::minus,
- /*AtParameterName=*/false,
- ReturnType, KeyIdents);
- cutOffParsing();
- return nullptr;
- }
- // Check for another keyword selector.
- SelIdent = ParseObjCSelectorPiece(selLoc);
- if (!SelIdent && Tok.isNot(tok::colon))
- break;
- if (!SelIdent) {
- SourceLocation ColonLoc = Tok.getLocation();
- if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
- Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
- Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
- Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
- }
- }
- // We have a selector or a colon, continue parsing.
- }
- bool isVariadic = false;
- bool cStyleParamWarned = false;
- // Parse the (optional) parameter list.
- while (Tok.is(tok::comma)) {
- ConsumeToken();
- if (Tok.is(tok::ellipsis)) {
- isVariadic = true;
- ConsumeToken();
- break;
- }
- if (!cStyleParamWarned) {
- Diag(Tok, diag::warn_cstyle_param);
- cStyleParamWarned = true;
- }
- DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
- // Parse the declarator.
- Declarator ParmDecl(DS, DeclaratorContext::PrototypeContext);
- ParseDeclarator(ParmDecl);
- IdentifierInfo *ParmII = ParmDecl.getIdentifier();
- Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
- CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
- ParmDecl.getIdentifierLoc(),
- Param,
- nullptr));
- }
- // FIXME: Add support for optional parameter list...
- // If attributes exist after the method, parse them.
- if (getLangOpts().ObjC)
- MaybeParseGNUAttributes(methodAttrs);
- MaybeParseCXX11Attributes(methodAttrs);
- if (KeyIdents.size() == 0)
- return nullptr;
- Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
- &KeyIdents[0]);
- Decl *Result = Actions.ActOnMethodDeclaration(
- getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
- Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
- MethodImplKind, isVariadic, MethodDefinition);
- PD.complete(Result);
- return Result;
- }
- /// objc-protocol-refs:
- /// '<' identifier-list '>'
- ///
- bool Parser::
- ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
- SmallVectorImpl<SourceLocation> &ProtocolLocs,
- bool WarnOnDeclarations, bool ForObjCContainer,
- SourceLocation &LAngleLoc, SourceLocation &EndLoc,
- bool consumeLastToken) {
- assert(Tok.is(tok::less) && "expected <");
- LAngleLoc = ConsumeToken(); // the "<"
- SmallVector<IdentifierLocPair, 8> ProtocolIdents;
- while (1) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
- cutOffParsing();
- return true;
- }
- if (expectIdentifier()) {
- SkipUntil(tok::greater, StopAtSemi);
- return true;
- }
- ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
- Tok.getLocation()));
- ProtocolLocs.push_back(Tok.getLocation());
- ConsumeToken();
- if (!TryConsumeToken(tok::comma))
- break;
- }
- // Consume the '>'.
- if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
- /*ObjCGenericList=*/false))
- return true;
- // Convert the list of protocols identifiers into a list of protocol decls.
- Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
- ProtocolIdents, Protocols);
- return false;
- }
- TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
- assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
- assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");
- SourceLocation lAngleLoc;
- SmallVector<Decl *, 8> protocols;
- SmallVector<SourceLocation, 8> protocolLocs;
- (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
- lAngleLoc, rAngleLoc,
- /*consumeLastToken=*/true);
- TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
- protocols,
- protocolLocs,
- rAngleLoc);
- if (result.isUsable()) {
- Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
- << FixItHint::CreateInsertion(lAngleLoc, "id")
- << SourceRange(lAngleLoc, rAngleLoc);
- }
- return result;
- }
- /// Parse Objective-C type arguments or protocol qualifiers.
- ///
- /// objc-type-arguments:
- /// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
- ///
- void Parser::parseObjCTypeArgsOrProtocolQualifiers(
- ParsedType baseType,
- SourceLocation &typeArgsLAngleLoc,
- SmallVectorImpl<ParsedType> &typeArgs,
- SourceLocation &typeArgsRAngleLoc,
- SourceLocation &protocolLAngleLoc,
- SmallVectorImpl<Decl *> &protocols,
- SmallVectorImpl<SourceLocation> &protocolLocs,
- SourceLocation &protocolRAngleLoc,
- bool consumeLastToken,
- bool warnOnIncompleteProtocols) {
- assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
- SourceLocation lAngleLoc = ConsumeToken();
- // Whether all of the elements we've parsed thus far are single
- // identifiers, which might be types or might be protocols.
- bool allSingleIdentifiers = true;
- SmallVector<IdentifierInfo *, 4> identifiers;
- SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
- // Parse a list of comma-separated identifiers, bailing out if we
- // see something different.
- do {
- // Parse a single identifier.
- if (Tok.is(tok::identifier) &&
- (NextToken().is(tok::comma) ||
- NextToken().is(tok::greater) ||
- NextToken().is(tok::greatergreater))) {
- identifiers.push_back(Tok.getIdentifierInfo());
- identifierLocs.push_back(ConsumeToken());
- continue;
- }
- if (Tok.is(tok::code_completion)) {
- // FIXME: Also include types here.
- SmallVector<IdentifierLocPair, 4> identifierLocPairs;
- for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
- identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
- identifierLocs[i]));
- }
- QualType BaseT = Actions.GetTypeFromParser(baseType);
- if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
- } else {
- Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
- }
- cutOffParsing();
- return;
- }
- allSingleIdentifiers = false;
- break;
- } while (TryConsumeToken(tok::comma));
- // If we parsed an identifier list, semantic analysis sorts out
- // whether it refers to protocols or to type arguments.
- if (allSingleIdentifiers) {
- // Parse the closing '>'.
- SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
- /*ObjCGenericList=*/true);
- // Let Sema figure out what we parsed.
- Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
- baseType,
- lAngleLoc,
- identifiers,
- identifierLocs,
- rAngleLoc,
- typeArgsLAngleLoc,
- typeArgs,
- typeArgsRAngleLoc,
- protocolLAngleLoc,
- protocols,
- protocolRAngleLoc,
- warnOnIncompleteProtocols);
- return;
- }
- // We parsed an identifier list but stumbled into non single identifiers, this
- // means we might (a) check that what we already parsed is a legitimate type
- // (not a protocol or unknown type) and (b) parse the remaining ones, which
- // must all be type args.
- // Convert the identifiers into type arguments.
- bool invalid = false;
- IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;
- SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;
- SmallVector<IdentifierInfo *, 2> unknownTypeArgs;
- SmallVector<SourceLocation, 2> unknownTypeArgsLoc;
- for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
- ParsedType typeArg
- = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
- if (typeArg) {
- DeclSpec DS(AttrFactory);
- const char *prevSpec = nullptr;
- unsigned diagID;
- DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
- typeArg, Actions.getASTContext().getPrintingPolicy());
- // Form a declarator to turn this into a type.
- Declarator D(DS, DeclaratorContext::TypeNameContext);
- TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
- if (fullTypeArg.isUsable()) {
- typeArgs.push_back(fullTypeArg.get());
- if (!foundValidTypeId) {
- foundValidTypeId = identifiers[i];
- foundValidTypeSrcLoc = identifierLocs[i];
- }
- } else {
- invalid = true;
- unknownTypeArgs.push_back(identifiers[i]);
- unknownTypeArgsLoc.push_back(identifierLocs[i]);
- }
- } else {
- invalid = true;
- if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) {
- unknownTypeArgs.push_back(identifiers[i]);
- unknownTypeArgsLoc.push_back(identifierLocs[i]);
- } else if (!foundProtocolId) {
- foundProtocolId = identifiers[i];
- foundProtocolSrcLoc = identifierLocs[i];
- }
- }
- }
- // Continue parsing type-names.
- do {
- Token CurTypeTok = Tok;
- TypeResult typeArg = ParseTypeName();
- // Consume the '...' for a pack expansion.
- SourceLocation ellipsisLoc;
- TryConsumeToken(tok::ellipsis, ellipsisLoc);
- if (typeArg.isUsable() && ellipsisLoc.isValid()) {
- typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
- }
- if (typeArg.isUsable()) {
- typeArgs.push_back(typeArg.get());
- if (!foundValidTypeId) {
- foundValidTypeId = CurTypeTok.getIdentifierInfo();
- foundValidTypeSrcLoc = CurTypeTok.getLocation();
- }
- } else {
- invalid = true;
- }
- } while (TryConsumeToken(tok::comma));
- // Diagnose the mix between type args and protocols.
- if (foundProtocolId && foundValidTypeId)
- Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
- foundValidTypeId,
- foundValidTypeSrcLoc);
- // Diagnose unknown arg types.
- ParsedType T;
- if (unknownTypeArgs.size())
- for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)
- Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],
- getCurScope(), nullptr, T);
- // Parse the closing '>'.
- SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
- /*ObjCGenericList=*/true);
- if (invalid) {
- typeArgs.clear();
- return;
- }
- // Record left/right angle locations.
- typeArgsLAngleLoc = lAngleLoc;
- typeArgsRAngleLoc = rAngleLoc;
- }
- void Parser::parseObjCTypeArgsAndProtocolQualifiers(
- ParsedType baseType,
- SourceLocation &typeArgsLAngleLoc,
- SmallVectorImpl<ParsedType> &typeArgs,
- SourceLocation &typeArgsRAngleLoc,
- SourceLocation &protocolLAngleLoc,
- SmallVectorImpl<Decl *> &protocols,
- SmallVectorImpl<SourceLocation> &protocolLocs,
- SourceLocation &protocolRAngleLoc,
- bool consumeLastToken) {
- assert(Tok.is(tok::less));
- // Parse the first angle-bracket-delimited clause.
- parseObjCTypeArgsOrProtocolQualifiers(baseType,
- typeArgsLAngleLoc,
- typeArgs,
- typeArgsRAngleLoc,
- protocolLAngleLoc,
- protocols,
- protocolLocs,
- protocolRAngleLoc,
- consumeLastToken,
- /*warnOnIncompleteProtocols=*/false);
- if (Tok.is(tok::eof)) // Nothing else to do here...
- return;
- // An Objective-C object pointer followed by type arguments
- // can then be followed again by a set of protocol references, e.g.,
- // \c NSArray<NSView><NSTextDelegate>
- if ((consumeLastToken && Tok.is(tok::less)) ||
- (!consumeLastToken && NextToken().is(tok::less))) {
- // If we aren't consuming the last token, the prior '>' is still hanging
- // there. Consume it before we parse the protocol qualifiers.
- if (!consumeLastToken)
- ConsumeToken();
- if (!protocols.empty()) {
- SkipUntilFlags skipFlags = SkipUntilFlags();
- if (!consumeLastToken)
- skipFlags = skipFlags | StopBeforeMatch;
- Diag(Tok, diag::err_objc_type_args_after_protocols)
- << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
- SkipUntil(tok::greater, tok::greatergreater, skipFlags);
- } else {
- ParseObjCProtocolReferences(protocols, protocolLocs,
- /*WarnOnDeclarations=*/false,
- /*ForObjCContainer=*/false,
- protocolLAngleLoc, protocolRAngleLoc,
- consumeLastToken);
- }
- }
- }
- TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
- SourceLocation loc,
- ParsedType type,
- bool consumeLastToken,
- SourceLocation &endLoc) {
- assert(Tok.is(tok::less));
- SourceLocation typeArgsLAngleLoc;
- SmallVector<ParsedType, 4> typeArgs;
- SourceLocation typeArgsRAngleLoc;
- SourceLocation protocolLAngleLoc;
- SmallVector<Decl *, 4> protocols;
- SmallVector<SourceLocation, 4> protocolLocs;
- SourceLocation protocolRAngleLoc;
- // Parse type arguments and protocol qualifiers.
- parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
- typeArgsRAngleLoc, protocolLAngleLoc,
- protocols, protocolLocs,
- protocolRAngleLoc, consumeLastToken);
- if (Tok.is(tok::eof))
- return true; // Invalid type result.
- // Compute the location of the last token.
- if (consumeLastToken)
- endLoc = PrevTokLocation;
- else
- endLoc = Tok.getLocation();
- return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
- getCurScope(),
- loc,
- type,
- typeArgsLAngleLoc,
- typeArgs,
- typeArgsRAngleLoc,
- protocolLAngleLoc,
- protocols,
- protocolLocs,
- protocolRAngleLoc);
- }
- void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
- BalancedDelimiterTracker &T,
- SmallVectorImpl<Decl *> &AllIvarDecls,
- bool RBraceMissing) {
- if (!RBraceMissing)
- T.consumeClose();
- Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
- Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
- Actions.ActOnObjCContainerFinishDefinition();
- // Call ActOnFields() even if we don't have any decls. This is useful
- // for code rewriting tools that need to be aware of the empty list.
- Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,
- T.getOpenLocation(), T.getCloseLocation(),
- ParsedAttributesView());
- }
- /// objc-class-instance-variables:
- /// '{' objc-instance-variable-decl-list[opt] '}'
- ///
- /// objc-instance-variable-decl-list:
- /// objc-visibility-spec
- /// objc-instance-variable-decl ';'
- /// ';'
- /// objc-instance-variable-decl-list objc-visibility-spec
- /// objc-instance-variable-decl-list objc-instance-variable-decl ';'
- /// objc-instance-variable-decl-list static_assert-declaration
- /// objc-instance-variable-decl-list ';'
- ///
- /// objc-visibility-spec:
- /// @private
- /// @protected
- /// @public
- /// @package [OBJC2]
- ///
- /// objc-instance-variable-decl:
- /// struct-declaration
- ///
- void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
- tok::ObjCKeywordKind visibility,
- SourceLocation atLoc) {
- assert(Tok.is(tok::l_brace) && "expected {");
- SmallVector<Decl *, 32> AllIvarDecls;
- ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
- ObjCDeclContextSwitch ObjCDC(*this);
- BalancedDelimiterTracker T(*this, tok::l_brace);
- T.consumeOpen();
- // While we still have something to read, read the instance variables.
- while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
- // Each iteration of this loop reads one objc-instance-variable-decl.
- // Check for extraneous top-level semicolon.
- if (Tok.is(tok::semi)) {
- ConsumeExtraSemi(InstanceVariableList);
- continue;
- }
- // Set the default visibility to private.
- if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtVisibility(getCurScope());
- return cutOffParsing();
- }
- switch (Tok.getObjCKeywordID()) {
- case tok::objc_private:
- case tok::objc_public:
- case tok::objc_protected:
- case tok::objc_package:
- visibility = Tok.getObjCKeywordID();
- ConsumeToken();
- continue;
- case tok::objc_end:
- Diag(Tok, diag::err_objc_unexpected_atend);
- Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
- Tok.setKind(tok::at);
- Tok.setLength(1);
- PP.EnterToken(Tok, /*IsReinject*/true);
- HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
- T, AllIvarDecls, true);
- return;
- default:
- Diag(Tok, diag::err_objc_illegal_visibility_spec);
- continue;
- }
- }
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(getCurScope(),
- Sema::PCC_ObjCInstanceVariableList);
- return cutOffParsing();
- }
- // This needs to duplicate a small amount of code from
- // ParseStructUnionBody() for things that should work in both
- // C struct and in Objective-C class instance variables.
- if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
- SourceLocation DeclEnd;
- ParseStaticAssertDeclaration(DeclEnd);
- continue;
- }
- auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
- Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
- // Install the declarator into the interface decl.
- FD.D.setObjCIvar(true);
- Decl *Field = Actions.ActOnIvar(
- getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
- FD.BitfieldSize, visibility);
- Actions.ActOnObjCContainerFinishDefinition();
- if (Field)
- AllIvarDecls.push_back(Field);
- FD.complete(Field);
- };
- // Parse all the comma separated declarators.
- ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, ObjCIvarCallback);
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- } else {
- Diag(Tok, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- }
- }
- HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
- T, AllIvarDecls, false);
- }
- /// objc-protocol-declaration:
- /// objc-protocol-definition
- /// objc-protocol-forward-reference
- ///
- /// objc-protocol-definition:
- /// \@protocol identifier
- /// objc-protocol-refs[opt]
- /// objc-interface-decl-list
- /// \@end
- ///
- /// objc-protocol-forward-reference:
- /// \@protocol identifier-list ';'
- ///
- /// "\@protocol identifier ;" should be resolved as "\@protocol
- /// identifier-list ;": objc-interface-decl-list may not start with a
- /// semicolon in the first alternative if objc-protocol-refs are omitted.
- Parser::DeclGroupPtrTy
- Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
- ParsedAttributes &attrs) {
- assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
- "ParseObjCAtProtocolDeclaration(): Expected @protocol");
- ConsumeToken(); // the "protocol" identifier
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCProtocolDecl(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- MaybeSkipAttributes(tok::objc_protocol);
- if (expectIdentifier())
- return nullptr; // missing protocol name.
- // Save the protocol name, then consume it.
- IdentifierInfo *protocolName = Tok.getIdentifierInfo();
- SourceLocation nameLoc = ConsumeToken();
- if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
- IdentifierLocPair ProtoInfo(protocolName, nameLoc);
- return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo, attrs);
- }
- CheckNestedObjCContexts(AtLoc);
- if (Tok.is(tok::comma)) { // list of forward declarations.
- SmallVector<IdentifierLocPair, 8> ProtocolRefs;
- ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
- // Parse the list of forward declarations.
- while (1) {
- ConsumeToken(); // the ','
- if (expectIdentifier()) {
- SkipUntil(tok::semi);
- return nullptr;
- }
- ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
- Tok.getLocation()));
- ConsumeToken(); // the identifier
- if (Tok.isNot(tok::comma))
- break;
- }
- // Consume the ';'.
- if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
- return nullptr;
- return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs);
- }
- // Last, and definitely not least, parse a protocol declaration.
- SourceLocation LAngleLoc, EndProtoLoc;
- SmallVector<Decl *, 8> ProtocolRefs;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
- LAngleLoc, EndProtoLoc,
- /*consumeLastToken=*/true))
- return nullptr;
- Decl *ProtoType = Actions.ActOnStartProtocolInterface(
- AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
- ProtocolLocs.data(), EndProtoLoc, attrs);
- ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
- return Actions.ConvertDeclToDeclGroup(ProtoType);
- }
- /// objc-implementation:
- /// objc-class-implementation-prologue
- /// objc-category-implementation-prologue
- ///
- /// objc-class-implementation-prologue:
- /// @implementation identifier objc-superclass[opt]
- /// objc-class-instance-variables[opt]
- ///
- /// objc-category-implementation-prologue:
- /// @implementation identifier ( identifier )
- Parser::DeclGroupPtrTy
- Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
- ParsedAttributes &Attrs) {
- assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
- "ParseObjCAtImplementationDeclaration(): Expected @implementation");
- CheckNestedObjCContexts(AtLoc);
- ConsumeToken(); // the "implementation" identifier
- // Code completion after '@implementation'.
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationDecl(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- MaybeSkipAttributes(tok::objc_implementation);
- if (expectIdentifier())
- return nullptr; // missing class or category name.
- // We have a class or category name - consume it.
- IdentifierInfo *nameId = Tok.getIdentifierInfo();
- SourceLocation nameLoc = ConsumeToken(); // consume class or category name
- Decl *ObjCImpDecl = nullptr;
- // Neither a type parameter list nor a list of protocol references is
- // permitted here. Parse and diagnose them.
- if (Tok.is(tok::less)) {
- SourceLocation lAngleLoc, rAngleLoc;
- SmallVector<IdentifierLocPair, 8> protocolIdents;
- SourceLocation diagLoc = Tok.getLocation();
- ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
- if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,
- protocolIdents, rAngleLoc)) {
- Diag(diagLoc, diag::err_objc_parameterized_implementation)
- << SourceRange(diagLoc, PrevTokLocation);
- } else if (lAngleLoc.isValid()) {
- Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
- << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
- }
- }
- if (Tok.is(tok::l_paren)) {
- // we have a category implementation.
- ConsumeParen();
- SourceLocation categoryLoc, rparenLoc;
- IdentifierInfo *categoryId = nullptr;
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
- cutOffParsing();
- return nullptr;
- }
- if (Tok.is(tok::identifier)) {
- categoryId = Tok.getIdentifierInfo();
- categoryLoc = ConsumeToken();
- } else {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing category name.
- return nullptr;
- }
- if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected) << tok::r_paren;
- SkipUntil(tok::r_paren); // don't stop at ';'
- return nullptr;
- }
- rparenLoc = ConsumeParen();
- if (Tok.is(tok::less)) { // we have illegal '<' try to recover
- Diag(Tok, diag::err_unexpected_protocol_qualifier);
- SourceLocation protocolLAngleLoc, protocolRAngleLoc;
- SmallVector<Decl *, 4> protocols;
- SmallVector<SourceLocation, 4> protocolLocs;
- (void)ParseObjCProtocolReferences(protocols, protocolLocs,
- /*warnOnIncompleteProtocols=*/false,
- /*ForObjCContainer=*/false,
- protocolLAngleLoc, protocolRAngleLoc,
- /*consumeLastToken=*/true);
- }
- ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
- AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);
- } else {
- // We have a class implementation
- SourceLocation superClassLoc;
- IdentifierInfo *superClassId = nullptr;
- if (TryConsumeToken(tok::colon)) {
- // We have a super class
- if (expectIdentifier())
- return nullptr; // missing super class name.
- superClassId = Tok.getIdentifierInfo();
- superClassLoc = ConsumeToken(); // Consume super class name
- }
- ObjCImpDecl = Actions.ActOnStartClassImplementation(
- AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);
- if (Tok.is(tok::l_brace)) // we have ivars
- ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
- else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
- Diag(Tok, diag::err_unexpected_protocol_qualifier);
- SourceLocation protocolLAngleLoc, protocolRAngleLoc;
- SmallVector<Decl *, 4> protocols;
- SmallVector<SourceLocation, 4> protocolLocs;
- (void)ParseObjCProtocolReferences(protocols, protocolLocs,
- /*warnOnIncompleteProtocols=*/false,
- /*ForObjCContainer=*/false,
- protocolLAngleLoc, protocolRAngleLoc,
- /*consumeLastToken=*/true);
- }
- }
- assert(ObjCImpDecl);
- SmallVector<Decl *, 8> DeclsInGroup;
- {
- ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
- while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
- DeclGroupRef DG = DGP.get();
- DeclsInGroup.append(DG.begin(), DG.end());
- }
- }
- }
- return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
- }
- Parser::DeclGroupPtrTy
- Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
- assert(Tok.isObjCAtKeyword(tok::objc_end) &&
- "ParseObjCAtEndDeclaration(): Expected @end");
- ConsumeToken(); // the "end" identifier
- if (CurParsedObjCImpl)
- CurParsedObjCImpl->finish(atEnd);
- else
- // missing @implementation
- Diag(atEnd.getBegin(), diag::err_expected_objc_container);
- return nullptr;
- }
- Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
- if (!Finished) {
- finish(P.Tok.getLocation());
- if (P.isEofOrEom()) {
- P.Diag(P.Tok, diag::err_objc_missing_end)
- << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
- P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)
- << Sema::OCK_Implementation;
- }
- }
- P.CurParsedObjCImpl = nullptr;
- assert(LateParsedObjCMethods.empty());
- }
- void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
- assert(!Finished);
- P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
- for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
- P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
- true/*Methods*/);
- P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
- if (HasCFunction)
- for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
- P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
- false/*c-functions*/);
- /// Clear and free the cached objc methods.
- for (LateParsedObjCMethodContainer::iterator
- I = LateParsedObjCMethods.begin(),
- E = LateParsedObjCMethods.end(); I != E; ++I)
- delete *I;
- LateParsedObjCMethods.clear();
- Finished = true;
- }
- /// compatibility-alias-decl:
- /// @compatibility_alias alias-name class-name ';'
- ///
- Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
- "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
- ConsumeToken(); // consume compatibility_alias
- if (expectIdentifier())
- return nullptr;
- IdentifierInfo *aliasId = Tok.getIdentifierInfo();
- SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
- if (expectIdentifier())
- return nullptr;
- IdentifierInfo *classId = Tok.getIdentifierInfo();
- SourceLocation classLoc = ConsumeToken(); // consume class-name;
- ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
- return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
- classId, classLoc);
- }
- /// property-synthesis:
- /// @synthesize property-ivar-list ';'
- ///
- /// property-ivar-list:
- /// property-ivar
- /// property-ivar-list ',' property-ivar
- ///
- /// property-ivar:
- /// identifier
- /// identifier '=' identifier
- ///
- Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
- "ParseObjCPropertySynthesize(): Expected '@synthesize'");
- ConsumeToken(); // consume synthesize
- while (true) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_synthesized_property_name);
- SkipUntil(tok::semi);
- return nullptr;
- }
- IdentifierInfo *propertyIvar = nullptr;
- IdentifierInfo *propertyId = Tok.getIdentifierInfo();
- SourceLocation propertyLoc = ConsumeToken(); // consume property name
- SourceLocation propertyIvarLoc;
- if (TryConsumeToken(tok::equal)) {
- // property '=' ivar-name
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
- cutOffParsing();
- return nullptr;
- }
- if (expectIdentifier())
- break;
- propertyIvar = Tok.getIdentifierInfo();
- propertyIvarLoc = ConsumeToken(); // consume ivar-name
- }
- Actions.ActOnPropertyImplDecl(
- getCurScope(), atLoc, propertyLoc, true,
- propertyId, propertyIvar, propertyIvarLoc,
- ObjCPropertyQueryKind::OBJC_PR_query_unknown);
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // consume ','
- }
- ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
- return nullptr;
- }
- /// property-dynamic:
- /// @dynamic property-list
- ///
- /// property-list:
- /// identifier
- /// property-list ',' identifier
- ///
- Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
- "ParseObjCPropertyDynamic(): Expected '@dynamic'");
- ConsumeToken(); // consume dynamic
- bool isClassProperty = false;
- if (Tok.is(tok::l_paren)) {
- ConsumeParen();
- const IdentifierInfo *II = Tok.getIdentifierInfo();
- if (!II) {
- Diag(Tok, diag::err_objc_expected_property_attr) << II;
- SkipUntil(tok::r_paren, StopAtSemi);
- } else {
- SourceLocation AttrName = ConsumeToken(); // consume attribute name
- if (II->isStr("class")) {
- isClassProperty = true;
- if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected) << tok::r_paren;
- SkipUntil(tok::r_paren, StopAtSemi);
- } else
- ConsumeParen();
- } else {
- Diag(AttrName, diag::err_objc_expected_property_attr) << II;
- SkipUntil(tok::r_paren, StopAtSemi);
- }
- }
- }
- while (true) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
- cutOffParsing();
- return nullptr;
- }
- if (expectIdentifier()) {
- SkipUntil(tok::semi);
- return nullptr;
- }
- IdentifierInfo *propertyId = Tok.getIdentifierInfo();
- SourceLocation propertyLoc = ConsumeToken(); // consume property name
- Actions.ActOnPropertyImplDecl(
- getCurScope(), atLoc, propertyLoc, false,
- propertyId, nullptr, SourceLocation(),
- isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
- ObjCPropertyQueryKind::OBJC_PR_query_unknown);
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // consume ','
- }
- ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
- return nullptr;
- }
- /// objc-throw-statement:
- /// throw expression[opt];
- ///
- StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
- ExprResult Res;
- ConsumeToken(); // consume throw
- if (Tok.isNot(tok::semi)) {
- Res = ParseExpression();
- if (Res.isInvalid()) {
- SkipUntil(tok::semi);
- return StmtError();
- }
- }
- // consume ';'
- ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
- return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
- }
- /// objc-synchronized-statement:
- /// @synchronized '(' expression ')' compound-statement
- ///
- StmtResult
- Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
- ConsumeToken(); // consume synchronized
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
- return StmtError();
- }
- // The operand is surrounded with parentheses.
- ConsumeParen(); // '('
- ExprResult operand(ParseExpression());
- if (Tok.is(tok::r_paren)) {
- ConsumeParen(); // ')'
- } else {
- if (!operand.isInvalid())
- Diag(Tok, diag::err_expected) << tok::r_paren;
- // Skip forward until we see a left brace, but don't consume it.
- SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
- }
- // Require a compound statement.
- if (Tok.isNot(tok::l_brace)) {
- if (!operand.isInvalid())
- Diag(Tok, diag::err_expected) << tok::l_brace;
- return StmtError();
- }
- // Check the @synchronized operand now.
- if (!operand.isInvalid())
- operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
- // Parse the compound statement within a new scope.
- ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
- StmtResult body(ParseCompoundStatementBody());
- bodyScope.Exit();
- // If there was a semantic or parse error earlier with the
- // operand, fail now.
- if (operand.isInvalid())
- return StmtError();
- if (body.isInvalid())
- body = Actions.ActOnNullStmt(Tok.getLocation());
- return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
- }
- /// objc-try-catch-statement:
- /// @try compound-statement objc-catch-list[opt]
- /// @try compound-statement objc-catch-list[opt] @finally compound-statement
- ///
- /// objc-catch-list:
- /// @catch ( parameter-declaration ) compound-statement
- /// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
- /// catch-parameter-declaration:
- /// parameter-declaration
- /// '...' [OBJC2]
- ///
- StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
- bool catch_or_finally_seen = false;
- ConsumeToken(); // consume try
- if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected) << tok::l_brace;
- return StmtError();
- }
- StmtVector CatchStmts;
- StmtResult FinallyStmt;
- ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
- StmtResult TryBody(ParseCompoundStatementBody());
- TryScope.Exit();
- if (TryBody.isInvalid())
- TryBody = Actions.ActOnNullStmt(Tok.getLocation());
- while (Tok.is(tok::at)) {
- // At this point, we need to lookahead to determine if this @ is the start
- // of an @catch or @finally. We don't want to consume the @ token if this
- // is an @try or @encode or something else.
- Token AfterAt = GetLookAheadToken(1);
- if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
- !AfterAt.isObjCAtKeyword(tok::objc_finally))
- break;
- SourceLocation AtCatchFinallyLoc = ConsumeToken();
- if (Tok.isObjCAtKeyword(tok::objc_catch)) {
- Decl *FirstPart = nullptr;
- ConsumeToken(); // consume catch
- if (Tok.is(tok::l_paren)) {
- ConsumeParen();
- ParseScope CatchScope(this, Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::AtCatchScope);
- if (Tok.isNot(tok::ellipsis)) {
- DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
- Declarator ParmDecl(DS, DeclaratorContext::ObjCCatchContext);
- ParseDeclarator(ParmDecl);
- // Inform the actions module about the declarator, so it
- // gets added to the current scope.
- FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
- } else
- ConsumeToken(); // consume '...'
- SourceLocation RParenLoc;
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else // Skip over garbage, until we get to ')'. Eat the ')'.
- SkipUntil(tok::r_paren, StopAtSemi);
- StmtResult CatchBody(true);
- if (Tok.is(tok::l_brace))
- CatchBody = ParseCompoundStatementBody();
- else
- Diag(Tok, diag::err_expected) << tok::l_brace;
- if (CatchBody.isInvalid())
- CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
- StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
- RParenLoc,
- FirstPart,
- CatchBody.get());
- if (!Catch.isInvalid())
- CatchStmts.push_back(Catch.get());
- } else {
- Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
- << "@catch clause";
- return StmtError();
- }
- catch_or_finally_seen = true;
- } else {
- assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
- ConsumeToken(); // consume finally
- ParseScope FinallyScope(this,
- Scope::DeclScope | Scope::CompoundStmtScope);
- bool ShouldCapture =
- getTargetInfo().getTriple().isWindowsMSVCEnvironment();
- if (ShouldCapture)
- Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),
- CR_ObjCAtFinally, 1);
- StmtResult FinallyBody(true);
- if (Tok.is(tok::l_brace))
- FinallyBody = ParseCompoundStatementBody();
- else
- Diag(Tok, diag::err_expected) << tok::l_brace;
- if (FinallyBody.isInvalid()) {
- FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
- if (ShouldCapture)
- Actions.ActOnCapturedRegionError();
- } else if (ShouldCapture) {
- FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());
- }
- FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
- FinallyBody.get());
- catch_or_finally_seen = true;
- break;
- }
- }
- if (!catch_or_finally_seen) {
- Diag(atLoc, diag::err_missing_catch_finally);
- return StmtError();
- }
- return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
- CatchStmts,
- FinallyStmt.get());
- }
- /// objc-autoreleasepool-statement:
- /// @autoreleasepool compound-statement
- ///
- StmtResult
- Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
- ConsumeToken(); // consume autoreleasepool
- if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected) << tok::l_brace;
- return StmtError();
- }
- // Enter a scope to hold everything within the compound stmt. Compound
- // statements can always hold declarations.
- ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
- StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
- BodyScope.Exit();
- if (AutoreleasePoolBody.isInvalid())
- AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
- return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
- AutoreleasePoolBody.get());
- }
- /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
- /// for later parsing.
- void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
- if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
- trySkippingFunctionBody()) {
- Actions.ActOnSkippedFunctionBody(MDecl);
- return;
- }
- LexedMethod* LM = new LexedMethod(this, MDecl);
- CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
- CachedTokens &Toks = LM->Toks;
- // Begin by storing the '{' or 'try' or ':' token.
- Toks.push_back(Tok);
- if (Tok.is(tok::kw_try)) {
- ConsumeToken();
- if (Tok.is(tok::colon)) {
- Toks.push_back(Tok);
- ConsumeToken();
- while (Tok.isNot(tok::l_brace)) {
- ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
- ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
- }
- }
- Toks.push_back(Tok); // also store '{'
- }
- else if (Tok.is(tok::colon)) {
- ConsumeToken();
- // FIXME: This is wrong, due to C++11 braced initialization.
- while (Tok.isNot(tok::l_brace)) {
- ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
- ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
- }
- Toks.push_back(Tok); // also store '{'
- }
- ConsumeBrace();
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
- while (Tok.is(tok::kw_catch)) {
- ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
- }
- }
- /// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
- ///
- Decl *Parser::ParseObjCMethodDefinition() {
- Decl *MDecl = ParseObjCMethodPrototype();
- PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),
- "parsing Objective-C method");
- // parse optional ';'
- if (Tok.is(tok::semi)) {
- if (CurParsedObjCImpl) {
- Diag(Tok, diag::warn_semicolon_before_method_body)
- << FixItHint::CreateRemoval(Tok.getLocation());
- }
- ConsumeToken();
- }
- // We should have an opening brace now.
- if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected_method_body);
- // Skip over garbage, until we get to '{'. Don't eat the '{'.
- SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
- // If we didn't find the '{', bail out.
- if (Tok.isNot(tok::l_brace))
- return nullptr;
- }
- if (!MDecl) {
- ConsumeBrace();
- SkipUntil(tok::r_brace);
- return nullptr;
- }
- // Allow the rest of sema to find private method decl implementations.
- Actions.AddAnyMethodToGlobalPool(MDecl);
- assert (CurParsedObjCImpl
- && "ParseObjCMethodDefinition - Method out of @implementation");
- // Consume the tokens and store them for later parsing.
- StashAwayMethodOrFunctionBodyTokens(MDecl);
- return MDecl;
- }
- StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
- ParsedStmtContext StmtCtx) {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtStatement(getCurScope());
- cutOffParsing();
- return StmtError();
- }
- if (Tok.isObjCAtKeyword(tok::objc_try))
- return ParseObjCTryStmt(AtLoc);
- if (Tok.isObjCAtKeyword(tok::objc_throw))
- return ParseObjCThrowStmt(AtLoc);
- if (Tok.isObjCAtKeyword(tok::objc_synchronized))
- return ParseObjCSynchronizedStmt(AtLoc);
- if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
- return ParseObjCAutoreleasePoolStmt(AtLoc);
- if (Tok.isObjCAtKeyword(tok::objc_import) &&
- getLangOpts().DebuggerSupport) {
- SkipUntil(tok::semi);
- return Actions.ActOnNullStmt(Tok.getLocation());
- }
- ExprStatementTokLoc = AtLoc;
- ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
- if (Res.isInvalid()) {
- // If the expression is invalid, skip ahead to the next semicolon. Not
- // doing this opens us up to the possibility of infinite loops if
- // ParseExpression does not consume any tokens.
- SkipUntil(tok::semi);
- return StmtError();
- }
- // Otherwise, eat the semicolon.
- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return handleExprStmt(Res, StmtCtx);
- }
- ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
- switch (Tok.getKind()) {
- case tok::code_completion:
- Actions.CodeCompleteObjCAtExpression(getCurScope());
- cutOffParsing();
- return ExprError();
- case tok::minus:
- case tok::plus: {
- tok::TokenKind Kind = Tok.getKind();
- SourceLocation OpLoc = ConsumeToken();
- if (!Tok.is(tok::numeric_constant)) {
- const char *Symbol = nullptr;
- switch (Kind) {
- case tok::minus: Symbol = "-"; break;
- case tok::plus: Symbol = "+"; break;
- default: llvm_unreachable("missing unary operator case");
- }
- Diag(Tok, diag::err_nsnumber_nonliteral_unary)
- << Symbol;
- return ExprError();
- }
- ExprResult Lit(Actions.ActOnNumericConstant(Tok));
- if (Lit.isInvalid()) {
- return Lit;
- }
- ConsumeToken(); // Consume the literal token.
- Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
- if (Lit.isInvalid())
- return Lit;
- return ParsePostfixExpressionSuffix(
- Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
- }
- case tok::string_literal: // primary-expression: string-literal
- case tok::wide_string_literal:
- return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
- case tok::char_constant:
- return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
- case tok::numeric_constant:
- return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
- case tok::kw_true: // Objective-C++, etc.
- case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
- return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
- case tok::kw_false: // Objective-C++, etc.
- case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
- return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
- case tok::l_square:
- // Objective-C array literal
- return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
- case tok::l_brace:
- // Objective-C dictionary literal
- return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
- case tok::l_paren:
- // Objective-C boxed expression
- return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
- default:
- if (Tok.getIdentifierInfo() == nullptr)
- return ExprError(Diag(AtLoc, diag::err_unexpected_at));
- switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
- case tok::objc_encode:
- return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
- case tok::objc_protocol:
- return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
- case tok::objc_selector:
- return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
- case tok::objc_available:
- return ParseAvailabilityCheckExpr(AtLoc);
- default: {
- const char *str = nullptr;
- // Only provide the @try/@finally/@autoreleasepool fixit when we're sure
- // that this is a proper statement where such directives could actually
- // occur.
- if (GetLookAheadToken(1).is(tok::l_brace) &&
- ExprStatementTokLoc == AtLoc) {
- char ch = Tok.getIdentifierInfo()->getNameStart()[0];
- str =
- ch == 't' ? "try"
- : (ch == 'f' ? "finally"
- : (ch == 'a' ? "autoreleasepool" : nullptr));
- }
- if (str) {
- SourceLocation kwLoc = Tok.getLocation();
- return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
- FixItHint::CreateReplacement(kwLoc, str));
- }
- else
- return ExprError(Diag(AtLoc, diag::err_unexpected_at));
- }
- }
- }
- }
- /// Parse the receiver of an Objective-C++ message send.
- ///
- /// This routine parses the receiver of a message send in
- /// Objective-C++ either as a type or as an expression. Note that this
- /// routine must not be called to parse a send to 'super', since it
- /// has no way to return such a result.
- ///
- /// \param IsExpr Whether the receiver was parsed as an expression.
- ///
- /// \param TypeOrExpr If the receiver was parsed as an expression (\c
- /// IsExpr is true), the parsed expression. If the receiver was parsed
- /// as a type (\c IsExpr is false), the parsed type.
- ///
- /// \returns True if an error occurred during parsing or semantic
- /// analysis, in which case the arguments do not have valid
- /// values. Otherwise, returns false for a successful parse.
- ///
- /// objc-receiver: [C++]
- /// 'super' [not parsed here]
- /// expression
- /// simple-type-specifier
- /// typename-specifier
- bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
- InMessageExpressionRAIIObject InMessage(*this, true);
- if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
- tok::annot_cxxscope))
- TryAnnotateTypeOrScopeToken();
- if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
- // objc-receiver:
- // expression
- // Make sure any typos in the receiver are corrected or diagnosed, so that
- // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
- // only the things that are valid ObjC receivers?
- ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
- if (Receiver.isInvalid())
- return true;
- IsExpr = true;
- TypeOrExpr = Receiver.get();
- return false;
- }
- // objc-receiver:
- // typename-specifier
- // simple-type-specifier
- // expression (that starts with one of the above)
- DeclSpec DS(AttrFactory);
- ParseCXXSimpleTypeSpecifier(DS);
- if (Tok.is(tok::l_paren)) {
- // If we see an opening parentheses at this point, we are
- // actually parsing an expression that starts with a
- // function-style cast, e.g.,
- //
- // postfix-expression:
- // simple-type-specifier ( expression-list [opt] )
- // typename-specifier ( expression-list [opt] )
- //
- // Parse the remainder of this case, then the (optional)
- // postfix-expression suffix, followed by the (optional)
- // right-hand side of the binary expression. We have an
- // instance method.
- ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
- if (!Receiver.isInvalid())
- Receiver = ParsePostfixExpressionSuffix(Receiver.get());
- if (!Receiver.isInvalid())
- Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
- if (Receiver.isInvalid())
- return true;
- IsExpr = true;
- TypeOrExpr = Receiver.get();
- return false;
- }
- // We have a class message. Turn the simple-type-specifier or
- // typename-specifier we parsed into a type and parse the
- // remainder of the class message.
- Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
- TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
- if (Type.isInvalid())
- return true;
- IsExpr = false;
- TypeOrExpr = Type.get().getAsOpaquePtr();
- return false;
- }
- /// Determine whether the parser is currently referring to a an
- /// Objective-C message send, using a simplified heuristic to avoid overhead.
- ///
- /// This routine will only return true for a subset of valid message-send
- /// expressions.
- bool Parser::isSimpleObjCMessageExpression() {
- assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&
- "Incorrect start for isSimpleObjCMessageExpression");
- return GetLookAheadToken(1).is(tok::identifier) &&
- GetLookAheadToken(2).is(tok::identifier);
- }
- bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
- if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||
- InMessageExpression)
- return false;
- ParsedType Type;
- if (Tok.is(tok::annot_typename))
- Type = getTypeAnnotation(Tok);
- else if (Tok.is(tok::identifier))
- Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
- getCurScope());
- else
- return false;
- if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
- const Token &AfterNext = GetLookAheadToken(2);
- if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
- if (Tok.is(tok::identifier))
- TryAnnotateTypeOrScopeToken();
- return Tok.is(tok::annot_typename);
- }
- }
- return false;
- }
- /// objc-message-expr:
- /// '[' objc-receiver objc-message-args ']'
- ///
- /// objc-receiver: [C]
- /// 'super'
- /// expression
- /// class-name
- /// type-name
- ///
- ExprResult Parser::ParseObjCMessageExpression() {
- assert(Tok.is(tok::l_square) && "'[' expected");
- SourceLocation LBracLoc = ConsumeBracket(); // consume '['
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMessageReceiver(getCurScope());
- cutOffParsing();
- return ExprError();
- }
- InMessageExpressionRAIIObject InMessage(*this, true);
- if (getLangOpts().CPlusPlus) {
- // We completely separate the C and C++ cases because C++ requires
- // more complicated (read: slower) parsing.
- // Handle send to super.
- // FIXME: This doesn't benefit from the same typo-correction we
- // get in Objective-C.
- if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
- NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
- return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
- nullptr);
- // Parse the receiver, which is either a type or an expression.
- bool IsExpr;
- void *TypeOrExpr = nullptr;
- if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- if (IsExpr)
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
- static_cast<Expr *>(TypeOrExpr));
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ParsedType::getFromOpaquePtr(TypeOrExpr),
- nullptr);
- }
- if (Tok.is(tok::identifier)) {
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation NameLoc = Tok.getLocation();
- ParsedType ReceiverType;
- switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
- Name == Ident_super,
- NextToken().is(tok::period),
- ReceiverType)) {
- case Sema::ObjCSuperMessage:
- return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
- nullptr);
- case Sema::ObjCClassMessage:
- if (!ReceiverType) {
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- ConsumeToken(); // the type name
- // Parse type arguments and protocol qualifiers.
- if (Tok.is(tok::less)) {
- SourceLocation NewEndLoc;
- TypeResult NewReceiverType
- = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
- /*consumeLastToken=*/true,
- NewEndLoc);
- if (!NewReceiverType.isUsable()) {
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- ReceiverType = NewReceiverType.get();
- }
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ReceiverType, nullptr);
- case Sema::ObjCInstanceMessage:
- // Fall through to parse an expression.
- break;
- }
- }
- // Otherwise, an arbitrary expression can be the receiver of a send.
- ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
- if (Res.isInvalid()) {
- SkipUntil(tok::r_square, StopAtSemi);
- return Res;
- }
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
- Res.get());
- }
- /// Parse the remainder of an Objective-C message following the
- /// '[' objc-receiver.
- ///
- /// This routine handles sends to super, class messages (sent to a
- /// class name), and instance messages (sent to an object), and the
- /// target is represented by \p SuperLoc, \p ReceiverType, or \p
- /// ReceiverExpr, respectively. Only one of these parameters may have
- /// a valid value.
- ///
- /// \param LBracLoc The location of the opening '['.
- ///
- /// \param SuperLoc If this is a send to 'super', the location of the
- /// 'super' keyword that indicates a send to the superclass.
- ///
- /// \param ReceiverType If this is a class message, the type of the
- /// class we are sending a message to.
- ///
- /// \param ReceiverExpr If this is an instance message, the expression
- /// used to compute the receiver object.
- ///
- /// objc-message-args:
- /// objc-selector
- /// objc-keywordarg-list
- ///
- /// objc-keywordarg-list:
- /// objc-keywordarg
- /// objc-keywordarg-list objc-keywordarg
- ///
- /// objc-keywordarg:
- /// selector-name[opt] ':' objc-keywordexpr
- ///
- /// objc-keywordexpr:
- /// nonempty-expr-list
- ///
- /// nonempty-expr-list:
- /// assignment-expression
- /// nonempty-expr-list , assignment-expression
- ///
- ExprResult
- Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
- SourceLocation SuperLoc,
- ParsedType ReceiverType,
- Expr *ReceiverExpr) {
- InMessageExpressionRAIIObject InMessage(*this, true);
- if (Tok.is(tok::code_completion)) {
- if (SuperLoc.isValid())
- Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
- false);
- else if (ReceiverType)
- Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
- false);
- else
- Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- None, false);
- cutOffParsing();
- return ExprError();
- }
- // Parse objc-selector
- SourceLocation Loc;
- IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
- SmallVector<IdentifierInfo *, 12> KeyIdents;
- SmallVector<SourceLocation, 12> KeyLocs;
- ExprVector KeyExprs;
- if (Tok.is(tok::colon)) {
- while (1) {
- // Each iteration parses a single keyword argument.
- KeyIdents.push_back(selIdent);
- KeyLocs.push_back(Loc);
- if (ExpectAndConsume(tok::colon)) {
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- /// Parse the expression after ':'
- if (Tok.is(tok::code_completion)) {
- if (SuperLoc.isValid())
- Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
- KeyIdents,
- /*AtArgumentExpression=*/true);
- else if (ReceiverType)
- Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
- KeyIdents,
- /*AtArgumentExpression=*/true);
- else
- Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- KeyIdents,
- /*AtArgumentExpression=*/true);
- cutOffParsing();
- return ExprError();
- }
- ExprResult Expr;
- if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
- Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
- Expr = ParseBraceInitializer();
- } else
- Expr = ParseAssignmentExpression();
- ExprResult Res(Expr);
- if (Res.isInvalid()) {
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return Res;
- }
- // We have a valid expression.
- KeyExprs.push_back(Res.get());
- // Code completion after each argument.
- if (Tok.is(tok::code_completion)) {
- if (SuperLoc.isValid())
- Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
- KeyIdents,
- /*AtArgumentExpression=*/false);
- else if (ReceiverType)
- Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
- KeyIdents,
- /*AtArgumentExpression=*/false);
- else
- Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- KeyIdents,
- /*AtArgumentExpression=*/false);
- cutOffParsing();
- return ExprError();
- }
- // Check for another keyword selector.
- selIdent = ParseObjCSelectorPiece(Loc);
- if (!selIdent && Tok.isNot(tok::colon))
- break;
- // We have a selector or a colon, continue parsing.
- }
- // Parse the, optional, argument list, comma separated.
- while (Tok.is(tok::comma)) {
- SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
- /// Parse the expression after ','
- ExprResult Res(ParseAssignmentExpression());
- if (Tok.is(tok::colon))
- Res = Actions.CorrectDelayedTyposInExpr(Res);
- if (Res.isInvalid()) {
- if (Tok.is(tok::colon)) {
- Diag(commaLoc, diag::note_extra_comma_message_arg) <<
- FixItHint::CreateRemoval(commaLoc);
- }
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return Res;
- }
- // We have a valid expression.
- KeyExprs.push_back(Res.get());
- }
- } else if (!selIdent) {
- Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- if (Tok.isNot(tok::r_square)) {
- Diag(Tok, diag::err_expected)
- << (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return ExprError();
- }
- SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
- unsigned nKeys = KeyIdents.size();
- if (nKeys == 0) {
- KeyIdents.push_back(selIdent);
- KeyLocs.push_back(Loc);
- }
- Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
- if (SuperLoc.isValid())
- return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
- LBracLoc, KeyLocs, RBracLoc, KeyExprs);
- else if (ReceiverType)
- return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
- LBracLoc, KeyLocs, RBracLoc, KeyExprs);
- return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
- LBracLoc, KeyLocs, RBracLoc, KeyExprs);
- }
- ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
- ExprResult Res(ParseStringLiteralExpression());
- if (Res.isInvalid()) return Res;
- // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
- // expressions. At this point, we know that the only valid thing that starts
- // with '@' is an @"".
- SmallVector<SourceLocation, 4> AtLocs;
- ExprVector AtStrings;
- AtLocs.push_back(AtLoc);
- AtStrings.push_back(Res.get());
- while (Tok.is(tok::at)) {
- AtLocs.push_back(ConsumeToken()); // eat the @.
- // Invalid unless there is a string literal.
- if (!isTokenStringLiteral())
- return ExprError(Diag(Tok, diag::err_objc_concat_string));
- ExprResult Lit(ParseStringLiteralExpression());
- if (Lit.isInvalid())
- return Lit;
- AtStrings.push_back(Lit.get());
- }
- return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
- }
- /// ParseObjCBooleanLiteral -
- /// objc-scalar-literal : '@' boolean-keyword
- /// ;
- /// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
- /// ;
- ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
- bool ArgValue) {
- SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
- return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
- }
- /// ParseObjCCharacterLiteral -
- /// objc-scalar-literal : '@' character-literal
- /// ;
- ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
- ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
- if (Lit.isInvalid()) {
- return Lit;
- }
- ConsumeToken(); // Consume the literal token.
- return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
- }
- /// ParseObjCNumericLiteral -
- /// objc-scalar-literal : '@' scalar-literal
- /// ;
- /// scalar-literal : | numeric-constant /* any numeric constant. */
- /// ;
- ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
- ExprResult Lit(Actions.ActOnNumericConstant(Tok));
- if (Lit.isInvalid()) {
- return Lit;
- }
- ConsumeToken(); // Consume the literal token.
- return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
- }
- /// ParseObjCBoxedExpr -
- /// objc-box-expression:
- /// @( assignment-expression )
- ExprResult
- Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
- if (Tok.isNot(tok::l_paren))
- return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- ExprResult ValueExpr(ParseAssignmentExpression());
- if (T.consumeClose())
- return ExprError();
- if (ValueExpr.isInvalid())
- return ExprError();
- // Wrap the sub-expression in a parenthesized expression, to distinguish
- // a boxed expression from a literal.
- SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
- ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
- return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
- ValueExpr.get());
- }
- ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
- ExprVector ElementExprs; // array elements.
- ConsumeBracket(); // consume the l_square.
- bool HasInvalidEltExpr = false;
- while (Tok.isNot(tok::r_square)) {
- // Parse list of array element expressions (all must be id types).
- ExprResult Res(ParseAssignmentExpression());
- if (Res.isInvalid()) {
- // We must manually skip to a ']', otherwise the expression skipper will
- // stop at the ']' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_square, StopAtSemi);
- return Res;
- }
- Res = Actions.CorrectDelayedTyposInExpr(Res.get());
- if (Res.isInvalid())
- HasInvalidEltExpr = true;
- // Parse the ellipsis that indicates a pack expansion.
- if (Tok.is(tok::ellipsis))
- Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
- if (Res.isInvalid())
- HasInvalidEltExpr = true;
- ElementExprs.push_back(Res.get());
- if (Tok.is(tok::comma))
- ConsumeToken(); // Eat the ','.
- else if (Tok.isNot(tok::r_square))
- return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
- << tok::comma);
- }
- SourceLocation EndLoc = ConsumeBracket(); // location of ']'
- if (HasInvalidEltExpr)
- return ExprError();
- MultiExprArg Args(ElementExprs);
- return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
- }
- ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
- SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
- ConsumeBrace(); // consume the l_square.
- bool HasInvalidEltExpr = false;
- while (Tok.isNot(tok::r_brace)) {
- // Parse the comma separated key : value expressions.
- ExprResult KeyExpr;
- {
- ColonProtectionRAIIObject X(*this);
- KeyExpr = ParseAssignmentExpression();
- if (KeyExpr.isInvalid()) {
- // We must manually skip to a '}', otherwise the expression skipper will
- // stop at the '}' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_brace, StopAtSemi);
- return KeyExpr;
- }
- }
- if (ExpectAndConsume(tok::colon)) {
- SkipUntil(tok::r_brace, StopAtSemi);
- return ExprError();
- }
- ExprResult ValueExpr(ParseAssignmentExpression());
- if (ValueExpr.isInvalid()) {
- // We must manually skip to a '}', otherwise the expression skipper will
- // stop at the '}' when it skips to the ';'. We want it to skip beyond
- // the enclosing expression.
- SkipUntil(tok::r_brace, StopAtSemi);
- return ValueExpr;
- }
- // Check the key and value for possible typos
- KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
- ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
- if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
- HasInvalidEltExpr = true;
- // Parse the ellipsis that designates this as a pack expansion. Do not
- // ActOnPackExpansion here, leave it to template instantiation time where
- // we can get better diagnostics.
- SourceLocation EllipsisLoc;
- if (getLangOpts().CPlusPlus)
- TryConsumeToken(tok::ellipsis, EllipsisLoc);
- // We have a valid expression. Collect it in a vector so we can
- // build the argument list.
- ObjCDictionaryElement Element = {
- KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
- };
- Elements.push_back(Element);
- if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
- return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
- << tok::comma);
- }
- SourceLocation EndLoc = ConsumeBrace();
- if (HasInvalidEltExpr)
- return ExprError();
- // Create the ObjCDictionaryLiteral.
- return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
- Elements);
- }
- /// objc-encode-expression:
- /// \@encode ( type-name )
- ExprResult
- Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
- SourceLocation EncLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren))
- return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- TypeResult Ty = ParseTypeName();
- T.consumeClose();
- if (Ty.isInvalid())
- return ExprError();
- return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
- Ty.get(), T.getCloseLocation());
- }
- /// objc-protocol-expression
- /// \@protocol ( protocol-name )
- ExprResult
- Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
- SourceLocation ProtoLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren))
- return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- if (expectIdentifier())
- return ExprError();
- IdentifierInfo *protocolId = Tok.getIdentifierInfo();
- SourceLocation ProtoIdLoc = ConsumeToken();
- T.consumeClose();
- return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
- T.getOpenLocation(), ProtoIdLoc,
- T.getCloseLocation());
- }
- /// objc-selector-expression
- /// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
- ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
- SourceLocation SelectorLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren))
- return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
- SmallVector<IdentifierInfo *, 12> KeyIdents;
- SourceLocation sLoc;
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- bool HasOptionalParen = Tok.is(tok::l_paren);
- if (HasOptionalParen)
- ConsumeParen();
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
- cutOffParsing();
- return ExprError();
- }
- IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
- if (!SelIdent && // missing selector name.
- Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
- return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
- KeyIdents.push_back(SelIdent);
- unsigned nColons = 0;
- if (Tok.isNot(tok::r_paren)) {
- while (1) {
- if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
- ++nColons;
- KeyIdents.push_back(nullptr);
- } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
- return ExprError();
- ++nColons;
- if (Tok.is(tok::r_paren))
- break;
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
- cutOffParsing();
- return ExprError();
- }
- // Check for another keyword selector.
- SourceLocation Loc;
- SelIdent = ParseObjCSelectorPiece(Loc);
- KeyIdents.push_back(SelIdent);
- if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
- break;
- }
- }
- if (HasOptionalParen && Tok.is(tok::r_paren))
- ConsumeParen(); // ')'
- T.consumeClose();
- Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
- return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
- T.getOpenLocation(),
- T.getCloseLocation(),
- !HasOptionalParen);
- }
- void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
- // MCDecl might be null due to error in method or c-function prototype, etc.
- Decl *MCDecl = LM.D;
- bool skip = MCDecl &&
- ((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
- (!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
- if (skip)
- return;
- // Save the current token position.
- SourceLocation OrigLoc = Tok.getLocation();
- assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
- // Store an artificial EOF token to ensure that we don't run off the end of
- // the method's body when we come to parse it.
- Token Eof;
- Eof.startToken();
- Eof.setKind(tok::eof);
- Eof.setEofData(MCDecl);
- Eof.setLocation(OrigLoc);
- LM.Toks.push_back(Eof);
- // Append the current token at the end of the new token stream so that it
- // doesn't get lost.
- LM.Toks.push_back(Tok);
- PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);
- // Consume the previously pushed token.
- ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
- assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
- "Inline objective-c method not starting with '{' or 'try' or ':'");
- // Enter a scope for the method or c-function body.
- ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
- Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
- // Tell the actions module that we have entered a method or c-function definition
- // with the specified Declarator for the method/function.
- if (parseMethod)
- Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
- else
- Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
- if (Tok.is(tok::kw_try))
- ParseFunctionTryBlock(MCDecl, BodyScope);
- else {
- if (Tok.is(tok::colon))
- ParseConstructorInitializer(MCDecl);
- else
- Actions.ActOnDefaultCtorInitializers(MCDecl);
- ParseFunctionStatementBody(MCDecl, BodyScope);
- }
- if (Tok.getLocation() != OrigLoc) {
- // Due to parsing error, we either went over the cached tokens or
- // there are still cached tokens left. If it's the latter case skip the
- // leftover tokens.
- // Since this is an uncommon situation that should be avoided, use the
- // expensive isBeforeInTranslationUnit call.
- if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
- OrigLoc))
- while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
- ConsumeAnyToken();
- }
- // Clean up the remaining EOF token.
- ConsumeAnyToken();
- }
|