123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758 |
- //===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
- //
- // 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 semantic analysis for Objective-C expressions.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/ExprObjC.h"
- #include "clang/AST/StmtVisitor.h"
- #include "clang/AST/TypeLoc.h"
- #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
- #include "clang/Basic/Builtins.h"
- #include "clang/Edit/Commit.h"
- #include "clang/Edit/Rewriters.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Sema/Initialization.h"
- #include "clang/Sema/Lookup.h"
- #include "clang/Sema/Scope.h"
- #include "clang/Sema/ScopeInfo.h"
- #include "clang/Sema/SemaInternal.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/Support/ConvertUTF.h"
- #include <optional>
- using namespace clang;
- using namespace sema;
- using llvm::ArrayRef;
- ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
- ArrayRef<Expr *> Strings) {
- // Most ObjC strings are formed out of a single piece. However, we *can*
- // have strings formed out of multiple @ strings with multiple pptokens in
- // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one
- // StringLiteral for ObjCStringLiteral to hold onto.
- StringLiteral *S = cast<StringLiteral>(Strings[0]);
- // If we have a multi-part string, merge it all together.
- if (Strings.size() != 1) {
- // Concatenate objc strings.
- SmallString<128> StrBuf;
- SmallVector<SourceLocation, 8> StrLocs;
- for (Expr *E : Strings) {
- S = cast<StringLiteral>(E);
- // ObjC strings can't be wide or UTF.
- if (!S->isOrdinary()) {
- Diag(S->getBeginLoc(), diag::err_cfstring_literal_not_string_constant)
- << S->getSourceRange();
- return true;
- }
- // Append the string.
- StrBuf += S->getString();
- // Get the locations of the string tokens.
- StrLocs.append(S->tokloc_begin(), S->tokloc_end());
- }
- // Create the aggregate string with the appropriate content and location
- // information.
- const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
- assert(CAT && "String literal not of constant array type!");
- QualType StrTy = Context.getConstantArrayType(
- CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr,
- CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
- S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ordinary,
- /*Pascal=*/false, StrTy, &StrLocs[0],
- StrLocs.size());
- }
- return BuildObjCStringLiteral(AtLocs[0], S);
- }
- ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
- // Verify that this composite string is acceptable for ObjC strings.
- if (CheckObjCString(S))
- return true;
- // Initialize the constant string interface lazily. This assumes
- // the NSString interface is seen in this translation unit. Note: We
- // don't use NSConstantString, since the runtime team considers this
- // interface private (even though it appears in the header files).
- QualType Ty = Context.getObjCConstantStringInterface();
- if (!Ty.isNull()) {
- Ty = Context.getObjCObjectPointerType(Ty);
- } else if (getLangOpts().NoConstantCFStrings) {
- IdentifierInfo *NSIdent=nullptr;
- std::string StringClass(getLangOpts().ObjCConstantStringClass);
- if (StringClass.empty())
- NSIdent = &Context.Idents.get("NSConstantString");
- else
- NSIdent = &Context.Idents.get(StringClass);
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
- LookupOrdinaryName);
- if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
- Context.setObjCConstantStringInterface(StrIF);
- Ty = Context.getObjCConstantStringInterface();
- Ty = Context.getObjCObjectPointerType(Ty);
- } else {
- // If there is no NSConstantString interface defined then treat this
- // as error and recover from it.
- Diag(S->getBeginLoc(), diag::err_no_nsconstant_string_class)
- << NSIdent << S->getSourceRange();
- Ty = Context.getObjCIdType();
- }
- } else {
- IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
- LookupOrdinaryName);
- if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
- Context.setObjCConstantStringInterface(StrIF);
- Ty = Context.getObjCConstantStringInterface();
- Ty = Context.getObjCObjectPointerType(Ty);
- } else {
- // If there is no NSString interface defined, implicitly declare
- // a @class NSString; and use that instead. This is to make sure
- // type of an NSString literal is represented correctly, instead of
- // being an 'id' type.
- Ty = Context.getObjCNSStringType();
- if (Ty.isNull()) {
- ObjCInterfaceDecl *NSStringIDecl =
- ObjCInterfaceDecl::Create (Context,
- Context.getTranslationUnitDecl(),
- SourceLocation(), NSIdent,
- nullptr, nullptr, SourceLocation());
- Ty = Context.getObjCInterfaceType(NSStringIDecl);
- Context.setObjCNSStringType(Ty);
- }
- Ty = Context.getObjCObjectPointerType(Ty);
- }
- }
- return new (Context) ObjCStringLiteral(S, Ty, AtLoc);
- }
- /// Emits an error if the given method does not exist, or if the return
- /// type is not an Objective-C object.
- static bool validateBoxingMethod(Sema &S, SourceLocation Loc,
- const ObjCInterfaceDecl *Class,
- Selector Sel, const ObjCMethodDecl *Method) {
- if (!Method) {
- // FIXME: Is there a better way to avoid quotes than using getName()?
- S.Diag(Loc, diag::err_undeclared_boxing_method) << Sel << Class->getName();
- return false;
- }
- // Make sure the return type is reasonable.
- QualType ReturnType = Method->getReturnType();
- if (!ReturnType->isObjCObjectPointerType()) {
- S.Diag(Loc, diag::err_objc_literal_method_sig)
- << Sel;
- S.Diag(Method->getLocation(), diag::note_objc_literal_method_return)
- << ReturnType;
- return false;
- }
- return true;
- }
- /// Maps ObjCLiteralKind to NSClassIdKindKind
- static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind(
- Sema::ObjCLiteralKind LiteralKind) {
- switch (LiteralKind) {
- case Sema::LK_Array:
- return NSAPI::ClassId_NSArray;
- case Sema::LK_Dictionary:
- return NSAPI::ClassId_NSDictionary;
- case Sema::LK_Numeric:
- return NSAPI::ClassId_NSNumber;
- case Sema::LK_String:
- return NSAPI::ClassId_NSString;
- case Sema::LK_Boxed:
- return NSAPI::ClassId_NSValue;
- // there is no corresponding matching
- // between LK_None/LK_Block and NSClassIdKindKind
- case Sema::LK_Block:
- case Sema::LK_None:
- break;
- }
- llvm_unreachable("LiteralKind can't be converted into a ClassKind");
- }
- /// Validates ObjCInterfaceDecl availability.
- /// ObjCInterfaceDecl, used to create ObjC literals, should be defined
- /// if clang not in a debugger mode.
- static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl,
- SourceLocation Loc,
- Sema::ObjCLiteralKind LiteralKind) {
- if (!Decl) {
- NSAPI::NSClassIdKindKind Kind = ClassKindFromLiteralKind(LiteralKind);
- IdentifierInfo *II = S.NSAPIObj->getNSClassId(Kind);
- S.Diag(Loc, diag::err_undeclared_objc_literal_class)
- << II->getName() << LiteralKind;
- return false;
- } else if (!Decl->hasDefinition() && !S.getLangOpts().DebuggerObjCLiteral) {
- S.Diag(Loc, diag::err_undeclared_objc_literal_class)
- << Decl->getName() << LiteralKind;
- S.Diag(Decl->getLocation(), diag::note_forward_class);
- return false;
- }
- return true;
- }
- /// Looks up ObjCInterfaceDecl of a given NSClassIdKindKind.
- /// Used to create ObjC literals, such as NSDictionary (@{}),
- /// NSArray (@[]) and Boxed Expressions (@())
- static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S,
- SourceLocation Loc,
- Sema::ObjCLiteralKind LiteralKind) {
- NSAPI::NSClassIdKindKind ClassKind = ClassKindFromLiteralKind(LiteralKind);
- IdentifierInfo *II = S.NSAPIObj->getNSClassId(ClassKind);
- NamedDecl *IF = S.LookupSingleName(S.TUScope, II, Loc,
- Sema::LookupOrdinaryName);
- ObjCInterfaceDecl *ID = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
- if (!ID && S.getLangOpts().DebuggerObjCLiteral) {
- ASTContext &Context = S.Context;
- TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
- ID = ObjCInterfaceDecl::Create (Context, TU, SourceLocation(), II,
- nullptr, nullptr, SourceLocation());
- }
- if (!ValidateObjCLiteralInterfaceDecl(S, ID, Loc, LiteralKind)) {
- ID = nullptr;
- }
- return ID;
- }
- /// Retrieve the NSNumber factory method that should be used to create
- /// an Objective-C literal for the given type.
- static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
- QualType NumberType,
- bool isLiteral = false,
- SourceRange R = SourceRange()) {
- std::optional<NSAPI::NSNumberLiteralMethodKind> Kind =
- S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
- if (!Kind) {
- if (isLiteral) {
- S.Diag(Loc, diag::err_invalid_nsnumber_type)
- << NumberType << R;
- }
- return nullptr;
- }
- // If we already looked up this method, we're done.
- if (S.NSNumberLiteralMethods[*Kind])
- return S.NSNumberLiteralMethods[*Kind];
- Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind,
- /*Instance=*/false);
- ASTContext &CX = S.Context;
- // Look up the NSNumber class, if we haven't done so already. It's cached
- // in the Sema instance.
- if (!S.NSNumberDecl) {
- S.NSNumberDecl = LookupObjCInterfaceDeclForLiteral(S, Loc,
- Sema::LK_Numeric);
- if (!S.NSNumberDecl) {
- return nullptr;
- }
- }
- if (S.NSNumberPointer.isNull()) {
- // generate the pointer to NSNumber type.
- QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl);
- S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject);
- }
- // Look for the appropriate method within NSNumber.
- ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);
- if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
- // create a stub definition this NSNumber factory method.
- TypeSourceInfo *ReturnTInfo = nullptr;
- Method =
- ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
- S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
- /*isInstance=*/false, /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false, ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
- ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
- SourceLocation(), SourceLocation(),
- &CX.Idents.get("value"),
- NumberType, /*TInfo=*/nullptr,
- SC_None, nullptr);
- Method->setMethodParams(S.Context, value, std::nullopt);
- }
- if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
- return nullptr;
- // Note: if the parameter type is out-of-line, we'll catch it later in the
- // implicit conversion.
- S.NSNumberLiteralMethods[*Kind] = Method;
- return Method;
- }
- /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
- /// numeric literal expression. Type of the expression will be "NSNumber *".
- ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
- // Determine the type of the literal.
- QualType NumberType = Number->getType();
- if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) {
- // In C, character literals have type 'int'. That's not the type we want
- // to use to determine the Objective-c literal kind.
- switch (Char->getKind()) {
- case CharacterLiteral::Ascii:
- case CharacterLiteral::UTF8:
- NumberType = Context.CharTy;
- break;
- case CharacterLiteral::Wide:
- NumberType = Context.getWideCharType();
- break;
- case CharacterLiteral::UTF16:
- NumberType = Context.Char16Ty;
- break;
- case CharacterLiteral::UTF32:
- NumberType = Context.Char32Ty;
- break;
- }
- }
- // Look for the appropriate method within NSNumber.
- // Construct the literal.
- SourceRange NR(Number->getSourceRange());
- ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType,
- true, NR);
- if (!Method)
- return ExprError();
- // Convert the number to the type that the parameter expects.
- ParmVarDecl *ParamDecl = Method->parameters()[0];
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- ParamDecl);
- ExprResult ConvertedNumber = PerformCopyInitialization(Entity,
- SourceLocation(),
- Number);
- if (ConvertedNumber.isInvalid())
- return ExprError();
- Number = ConvertedNumber.get();
- // Use the effective source range of the literal, including the leading '@'.
- return MaybeBindToTemporary(
- new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method,
- SourceRange(AtLoc, NR.getEnd())));
- }
- ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc,
- SourceLocation ValueLoc,
- bool Value) {
- ExprResult Inner;
- if (getLangOpts().CPlusPlus) {
- Inner = ActOnCXXBoolLiteral(ValueLoc, Value? tok::kw_true : tok::kw_false);
- } else {
- // C doesn't actually have a way to represent literal values of type
- // _Bool. So, we'll use 0/1 and implicit cast to _Bool.
- Inner = ActOnIntegerConstant(ValueLoc, Value? 1 : 0);
- Inner = ImpCastExprToType(Inner.get(), Context.BoolTy,
- CK_IntegralToBoolean);
- }
- return BuildObjCNumericLiteral(AtLoc, Inner.get());
- }
- /// Check that the given expression is a valid element of an Objective-C
- /// collection literal.
- static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
- QualType T,
- bool ArrayLiteral = false) {
- // If the expression is type-dependent, there's nothing for us to do.
- if (Element->isTypeDependent())
- return Element;
- ExprResult Result = S.CheckPlaceholderExpr(Element);
- if (Result.isInvalid())
- return ExprError();
- Element = Result.get();
- // In C++, check for an implicit conversion to an Objective-C object pointer
- // type.
- if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) {
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(S.Context, T,
- /*Consumed=*/false);
- InitializationKind Kind = InitializationKind::CreateCopy(
- Element->getBeginLoc(), SourceLocation());
- InitializationSequence Seq(S, Entity, Kind, Element);
- if (!Seq.Failed())
- return Seq.Perform(S, Entity, Kind, Element);
- }
- Expr *OrigElement = Element;
- // Perform lvalue-to-rvalue conversion.
- Result = S.DefaultLvalueConversion(Element);
- if (Result.isInvalid())
- return ExprError();
- Element = Result.get();
- // Make sure that we have an Objective-C pointer type or block.
- if (!Element->getType()->isObjCObjectPointerType() &&
- !Element->getType()->isBlockPointerType()) {
- bool Recovered = false;
- // If this is potentially an Objective-C numeric literal, add the '@'.
- if (isa<IntegerLiteral>(OrigElement) ||
- isa<CharacterLiteral>(OrigElement) ||
- isa<FloatingLiteral>(OrigElement) ||
- isa<ObjCBoolLiteralExpr>(OrigElement) ||
- isa<CXXBoolLiteralExpr>(OrigElement)) {
- if (S.NSAPIObj->getNSNumberFactoryMethodKind(OrigElement->getType())) {
- int Which = isa<CharacterLiteral>(OrigElement) ? 1
- : (isa<CXXBoolLiteralExpr>(OrigElement) ||
- isa<ObjCBoolLiteralExpr>(OrigElement)) ? 2
- : 3;
- S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection)
- << Which << OrigElement->getSourceRange()
- << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@");
- Result =
- S.BuildObjCNumericLiteral(OrigElement->getBeginLoc(), OrigElement);
- if (Result.isInvalid())
- return ExprError();
- Element = Result.get();
- Recovered = true;
- }
- }
- // If this is potentially an Objective-C string literal, add the '@'.
- else if (StringLiteral *String = dyn_cast<StringLiteral>(OrigElement)) {
- if (String->isOrdinary()) {
- S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection)
- << 0 << OrigElement->getSourceRange()
- << FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@");
- Result = S.BuildObjCStringLiteral(OrigElement->getBeginLoc(), String);
- if (Result.isInvalid())
- return ExprError();
- Element = Result.get();
- Recovered = true;
- }
- }
- if (!Recovered) {
- S.Diag(Element->getBeginLoc(), diag::err_invalid_collection_element)
- << Element->getType();
- return ExprError();
- }
- }
- if (ArrayLiteral)
- if (ObjCStringLiteral *getString =
- dyn_cast<ObjCStringLiteral>(OrigElement)) {
- if (StringLiteral *SL = getString->getString()) {
- unsigned numConcat = SL->getNumConcatenated();
- if (numConcat > 1) {
- // Only warn if the concatenated string doesn't come from a macro.
- bool hasMacro = false;
- for (unsigned i = 0; i < numConcat ; ++i)
- if (SL->getStrTokenLoc(i).isMacroID()) {
- hasMacro = true;
- break;
- }
- if (!hasMacro)
- S.Diag(Element->getBeginLoc(),
- diag::warn_concatenated_nsarray_literal)
- << Element->getType();
- }
- }
- }
- // Make sure that the element has the type that the container factory
- // function expects.
- return S.PerformCopyInitialization(
- InitializedEntity::InitializeParameter(S.Context, T,
- /*Consumed=*/false),
- Element->getBeginLoc(), Element);
- }
- ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
- if (ValueExpr->isTypeDependent()) {
- ObjCBoxedExpr *BoxedExpr =
- new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, nullptr, SR);
- return BoxedExpr;
- }
- ObjCMethodDecl *BoxingMethod = nullptr;
- QualType BoxedType;
- // Convert the expression to an RValue, so we can check for pointer types...
- ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr);
- if (RValue.isInvalid()) {
- return ExprError();
- }
- SourceLocation Loc = SR.getBegin();
- ValueExpr = RValue.get();
- QualType ValueType(ValueExpr->getType());
- if (const PointerType *PT = ValueType->getAs<PointerType>()) {
- QualType PointeeType = PT->getPointeeType();
- if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
- if (!NSStringDecl) {
- NSStringDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
- Sema::LK_String);
- if (!NSStringDecl) {
- return ExprError();
- }
- QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl);
- NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
- }
- // The boxed expression can be emitted as a compile time constant if it is
- // a string literal whose character encoding is compatible with UTF-8.
- if (auto *CE = dyn_cast<ImplicitCastExpr>(ValueExpr))
- if (CE->getCastKind() == CK_ArrayToPointerDecay)
- if (auto *SL =
- dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) {
- assert((SL->isOrdinary() || SL->isUTF8()) &&
- "unexpected character encoding");
- StringRef Str = SL->getString();
- const llvm::UTF8 *StrBegin = Str.bytes_begin();
- const llvm::UTF8 *StrEnd = Str.bytes_end();
- // Check that this is a valid UTF-8 string.
- if (llvm::isLegalUTF8String(&StrBegin, StrEnd)) {
- BoxedType = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(
- NullabilityKind::NonNull),
- NSStringPointer, NSStringPointer);
- return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR);
- }
- Diag(SL->getBeginLoc(), diag::warn_objc_boxing_invalid_utf8_string)
- << NSStringPointer << SL->getSourceRange();
- }
- if (!StringWithUTF8StringMethod) {
- IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
- Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
- // Look for the appropriate method within NSString.
- BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String);
- if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
- // Debugger needs to work even if NSString hasn't been defined.
- TypeSourceInfo *ReturnTInfo = nullptr;
- ObjCMethodDecl *M = ObjCMethodDecl::Create(
- Context, SourceLocation(), SourceLocation(), stringWithUTF8String,
- NSStringPointer, ReturnTInfo, NSStringDecl,
- /*isInstance=*/false, /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false, ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
- QualType ConstCharType = Context.CharTy.withConst();
- ParmVarDecl *value =
- ParmVarDecl::Create(Context, M,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("value"),
- Context.getPointerType(ConstCharType),
- /*TInfo=*/nullptr,
- SC_None, nullptr);
- M->setMethodParams(Context, value, std::nullopt);
- BoxingMethod = M;
- }
- if (!validateBoxingMethod(*this, Loc, NSStringDecl,
- stringWithUTF8String, BoxingMethod))
- return ExprError();
- StringWithUTF8StringMethod = BoxingMethod;
- }
- BoxingMethod = StringWithUTF8StringMethod;
- BoxedType = NSStringPointer;
- // Transfer the nullability from method's return type.
- std::optional<NullabilityKind> Nullability =
- BoxingMethod->getReturnType()->getNullability();
- if (Nullability)
- BoxedType = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
- BoxedType);
- }
- } else if (ValueType->isBuiltinType()) {
- // The other types we support are numeric, char and BOOL/bool. We could also
- // provide limited support for structure types, such as NSRange, NSRect, and
- // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h>
- // for more details.
- // Check for a top-level character literal.
- if (const CharacterLiteral *Char =
- dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) {
- // In C, character literals have type 'int'. That's not the type we want
- // to use to determine the Objective-c literal kind.
- switch (Char->getKind()) {
- case CharacterLiteral::Ascii:
- case CharacterLiteral::UTF8:
- ValueType = Context.CharTy;
- break;
- case CharacterLiteral::Wide:
- ValueType = Context.getWideCharType();
- break;
- case CharacterLiteral::UTF16:
- ValueType = Context.Char16Ty;
- break;
- case CharacterLiteral::UTF32:
- ValueType = Context.Char32Ty;
- break;
- }
- }
- // FIXME: Do I need to do anything special with BoolTy expressions?
- // Look for the appropriate method within NSNumber.
- BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType);
- BoxedType = NSNumberPointer;
- } else if (const EnumType *ET = ValueType->getAs<EnumType>()) {
- if (!ET->getDecl()->isComplete()) {
- Diag(Loc, diag::err_objc_incomplete_boxed_expression_type)
- << ValueType << ValueExpr->getSourceRange();
- return ExprError();
- }
- BoxingMethod = getNSNumberFactoryMethod(*this, Loc,
- ET->getDecl()->getIntegerType());
- BoxedType = NSNumberPointer;
- } else if (ValueType->isObjCBoxableRecordType()) {
- // Support for structure types, that marked as objc_boxable
- // struct __attribute__((objc_boxable)) s { ... };
- // Look up the NSValue class, if we haven't done so already. It's cached
- // in the Sema instance.
- if (!NSValueDecl) {
- NSValueDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
- Sema::LK_Boxed);
- if (!NSValueDecl) {
- return ExprError();
- }
- // generate the pointer to NSValue type.
- QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl);
- NSValuePointer = Context.getObjCObjectPointerType(NSValueObject);
- }
- if (!ValueWithBytesObjCTypeMethod) {
- IdentifierInfo *II[] = {
- &Context.Idents.get("valueWithBytes"),
- &Context.Idents.get("objCType")
- };
- Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II);
- // Look for the appropriate method within NSValue.
- BoxingMethod = NSValueDecl->lookupClassMethod(ValueWithBytesObjCType);
- if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
- // Debugger needs to work even if NSValue hasn't been defined.
- TypeSourceInfo *ReturnTInfo = nullptr;
- ObjCMethodDecl *M = ObjCMethodDecl::Create(
- Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType,
- NSValuePointer, ReturnTInfo, NSValueDecl,
- /*isInstance=*/false,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false, ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
- SmallVector<ParmVarDecl *, 2> Params;
- ParmVarDecl *bytes =
- ParmVarDecl::Create(Context, M,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("bytes"),
- Context.VoidPtrTy.withConst(),
- /*TInfo=*/nullptr,
- SC_None, nullptr);
- Params.push_back(bytes);
- QualType ConstCharType = Context.CharTy.withConst();
- ParmVarDecl *type =
- ParmVarDecl::Create(Context, M,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("type"),
- Context.getPointerType(ConstCharType),
- /*TInfo=*/nullptr,
- SC_None, nullptr);
- Params.push_back(type);
- M->setMethodParams(Context, Params, std::nullopt);
- BoxingMethod = M;
- }
- if (!validateBoxingMethod(*this, Loc, NSValueDecl,
- ValueWithBytesObjCType, BoxingMethod))
- return ExprError();
- ValueWithBytesObjCTypeMethod = BoxingMethod;
- }
- if (!ValueType.isTriviallyCopyableType(Context)) {
- Diag(Loc, diag::err_objc_non_trivially_copyable_boxed_expression_type)
- << ValueType << ValueExpr->getSourceRange();
- return ExprError();
- }
- BoxingMethod = ValueWithBytesObjCTypeMethod;
- BoxedType = NSValuePointer;
- }
- if (!BoxingMethod) {
- Diag(Loc, diag::err_objc_illegal_boxed_expression_type)
- << ValueType << ValueExpr->getSourceRange();
- return ExprError();
- }
- DiagnoseUseOfDecl(BoxingMethod, Loc);
- ExprResult ConvertedValueExpr;
- if (ValueType->isObjCBoxableRecordType()) {
- InitializedEntity IE = InitializedEntity::InitializeTemporary(ValueType);
- ConvertedValueExpr = PerformCopyInitialization(IE, ValueExpr->getExprLoc(),
- ValueExpr);
- } else {
- // Convert the expression to the type that the parameter requires.
- ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0];
- InitializedEntity IE = InitializedEntity::InitializeParameter(Context,
- ParamDecl);
- ConvertedValueExpr = PerformCopyInitialization(IE, SourceLocation(),
- ValueExpr);
- }
- if (ConvertedValueExpr.isInvalid())
- return ExprError();
- ValueExpr = ConvertedValueExpr.get();
- ObjCBoxedExpr *BoxedExpr =
- new (Context) ObjCBoxedExpr(ValueExpr, BoxedType,
- BoxingMethod, SR);
- return MaybeBindToTemporary(BoxedExpr);
- }
- /// Build an ObjC subscript pseudo-object expression, given that
- /// that's supported by the runtime.
- ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
- Expr *IndexExpr,
- ObjCMethodDecl *getterMethod,
- ObjCMethodDecl *setterMethod) {
- assert(!LangOpts.isSubscriptPointerArithmetic());
- // We can't get dependent types here; our callers should have
- // filtered them out.
- assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
- "base or index cannot have dependent type here");
- // Filter out placeholders in the index. In theory, overloads could
- // be preserved here, although that might not actually work correctly.
- ExprResult Result = CheckPlaceholderExpr(IndexExpr);
- if (Result.isInvalid())
- return ExprError();
- IndexExpr = Result.get();
- // Perform lvalue-to-rvalue conversion on the base.
- Result = DefaultLvalueConversion(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.get();
- // Build the pseudo-object expression.
- return new (Context) ObjCSubscriptRefExpr(
- BaseExpr, IndexExpr, Context.PseudoObjectTy, VK_LValue, OK_ObjCSubscript,
- getterMethod, setterMethod, RB);
- }
- ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
- SourceLocation Loc = SR.getBegin();
- if (!NSArrayDecl) {
- NSArrayDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
- Sema::LK_Array);
- if (!NSArrayDecl) {
- return ExprError();
- }
- }
- // Find the arrayWithObjects:count: method, if we haven't done so already.
- QualType IdT = Context.getObjCIdType();
- if (!ArrayWithObjectsMethod) {
- Selector
- Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount);
- ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel);
- if (!Method && getLangOpts().DebuggerObjCLiteral) {
- TypeSourceInfo *ReturnTInfo = nullptr;
- Method = ObjCMethodDecl::Create(
- Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
- Context.getTranslationUnitDecl(), false /*Instance*/,
- false /*isVariadic*/,
- /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required, false);
- SmallVector<ParmVarDecl *, 2> Params;
- ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("objects"),
- Context.getPointerType(IdT),
- /*TInfo=*/nullptr,
- SC_None, nullptr);
- Params.push_back(objects);
- ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("cnt"),
- Context.UnsignedLongTy,
- /*TInfo=*/nullptr, SC_None,
- nullptr);
- Params.push_back(cnt);
- Method->setMethodParams(Context, Params, std::nullopt);
- }
- if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method))
- return ExprError();
- // Dig out the type that all elements should be converted to.
- QualType T = Method->parameters()[0]->getType();
- const PointerType *PtrT = T->getAs<PointerType>();
- if (!PtrT ||
- !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << Sel;
- Diag(Method->parameters()[0]->getLocation(),
- diag::note_objc_literal_method_param)
- << 0 << T
- << Context.getPointerType(IdT.withConst());
- return ExprError();
- }
- // Check that the 'count' parameter is integral.
- if (!Method->parameters()[1]->getType()->isIntegerType()) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << Sel;
- Diag(Method->parameters()[1]->getLocation(),
- diag::note_objc_literal_method_param)
- << 1
- << Method->parameters()[1]->getType()
- << "integral";
- return ExprError();
- }
- // We've found a good +arrayWithObjects:count: method. Save it!
- ArrayWithObjectsMethod = Method;
- }
- QualType ObjectsType = ArrayWithObjectsMethod->parameters()[0]->getType();
- QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType();
- // Check that each of the elements provided is valid in a collection literal,
- // performing conversions as necessary.
- Expr **ElementsBuffer = Elements.data();
- for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
- ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
- ElementsBuffer[I],
- RequiredType, true);
- if (Converted.isInvalid())
- return ExprError();
- ElementsBuffer[I] = Converted.get();
- }
- QualType Ty
- = Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(NSArrayDecl));
- return MaybeBindToTemporary(
- ObjCArrayLiteral::Create(Context, Elements, Ty,
- ArrayWithObjectsMethod, SR));
- }
- /// Check for duplicate keys in an ObjC dictionary literal. For instance:
- /// NSDictionary *nd = @{ @"foo" : @"bar", @"foo" : @"baz" };
- static void
- CheckObjCDictionaryLiteralDuplicateKeys(Sema &S,
- ObjCDictionaryLiteral *Literal) {
- if (Literal->isValueDependent() || Literal->isTypeDependent())
- return;
- // NSNumber has quite relaxed equality semantics (for instance, @YES is
- // considered equal to @1.0). For now, ignore floating points and just do a
- // bit-width and sign agnostic integer compare.
- struct APSIntCompare {
- bool operator()(const llvm::APSInt &LHS, const llvm::APSInt &RHS) const {
- return llvm::APSInt::compareValues(LHS, RHS) < 0;
- }
- };
- llvm::DenseMap<StringRef, SourceLocation> StringKeys;
- std::map<llvm::APSInt, SourceLocation, APSIntCompare> IntegralKeys;
- auto checkOneKey = [&](auto &Map, const auto &Key, SourceLocation Loc) {
- auto Pair = Map.insert({Key, Loc});
- if (!Pair.second) {
- S.Diag(Loc, diag::warn_nsdictionary_duplicate_key);
- S.Diag(Pair.first->second, diag::note_nsdictionary_duplicate_key_here);
- }
- };
- for (unsigned Idx = 0, End = Literal->getNumElements(); Idx != End; ++Idx) {
- Expr *Key = Literal->getKeyValueElement(Idx).Key->IgnoreParenImpCasts();
- if (auto *StrLit = dyn_cast<ObjCStringLiteral>(Key)) {
- StringRef Bytes = StrLit->getString()->getBytes();
- SourceLocation Loc = StrLit->getExprLoc();
- checkOneKey(StringKeys, Bytes, Loc);
- }
- if (auto *BE = dyn_cast<ObjCBoxedExpr>(Key)) {
- Expr *Boxed = BE->getSubExpr();
- SourceLocation Loc = BE->getExprLoc();
- // Check for @("foo").
- if (auto *Str = dyn_cast<StringLiteral>(Boxed->IgnoreParenImpCasts())) {
- checkOneKey(StringKeys, Str->getBytes(), Loc);
- continue;
- }
- Expr::EvalResult Result;
- if (Boxed->EvaluateAsInt(Result, S.getASTContext(),
- Expr::SE_AllowSideEffects)) {
- checkOneKey(IntegralKeys, Result.Val.getInt(), Loc);
- }
- }
- }
- }
- ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
- MutableArrayRef<ObjCDictionaryElement> Elements) {
- SourceLocation Loc = SR.getBegin();
- if (!NSDictionaryDecl) {
- NSDictionaryDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
- Sema::LK_Dictionary);
- if (!NSDictionaryDecl) {
- return ExprError();
- }
- }
- // Find the dictionaryWithObjects:forKeys:count: method, if we haven't done
- // so already.
- QualType IdT = Context.getObjCIdType();
- if (!DictionaryWithObjectsMethod) {
- Selector Sel = NSAPIObj->getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
- ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
- if (!Method && getLangOpts().DebuggerObjCLiteral) {
- Method = ObjCMethodDecl::Create(
- Context, SourceLocation(), SourceLocation(), Sel, IdT,
- nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(),
- false /*Instance*/, false /*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required, false);
- SmallVector<ParmVarDecl *, 3> Params;
- ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("objects"),
- Context.getPointerType(IdT),
- /*TInfo=*/nullptr, SC_None,
- nullptr);
- Params.push_back(objects);
- ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("keys"),
- Context.getPointerType(IdT),
- /*TInfo=*/nullptr, SC_None,
- nullptr);
- Params.push_back(keys);
- ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("cnt"),
- Context.UnsignedLongTy,
- /*TInfo=*/nullptr, SC_None,
- nullptr);
- Params.push_back(cnt);
- Method->setMethodParams(Context, Params, std::nullopt);
- }
- if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel,
- Method))
- return ExprError();
- // Dig out the type that all values should be converted to.
- QualType ValueT = Method->parameters()[0]->getType();
- const PointerType *PtrValue = ValueT->getAs<PointerType>();
- if (!PtrValue ||
- !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << Sel;
- Diag(Method->parameters()[0]->getLocation(),
- diag::note_objc_literal_method_param)
- << 0 << ValueT
- << Context.getPointerType(IdT.withConst());
- return ExprError();
- }
- // Dig out the type that all keys should be converted to.
- QualType KeyT = Method->parameters()[1]->getType();
- const PointerType *PtrKey = KeyT->getAs<PointerType>();
- if (!PtrKey ||
- !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
- IdT)) {
- bool err = true;
- if (PtrKey) {
- if (QIDNSCopying.isNull()) {
- // key argument of selector is id<NSCopying>?
- if (ObjCProtocolDecl *NSCopyingPDecl =
- LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
- ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
- QIDNSCopying = Context.getObjCObjectType(
- Context.ObjCBuiltinIdTy, {},
- llvm::ArrayRef((ObjCProtocolDecl **)PQ, 1), false);
- QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
- }
- }
- if (!QIDNSCopying.isNull())
- err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
- QIDNSCopying);
- }
- if (err) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << Sel;
- Diag(Method->parameters()[1]->getLocation(),
- diag::note_objc_literal_method_param)
- << 1 << KeyT
- << Context.getPointerType(IdT.withConst());
- return ExprError();
- }
- }
- // Check that the 'count' parameter is integral.
- QualType CountType = Method->parameters()[2]->getType();
- if (!CountType->isIntegerType()) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << Sel;
- Diag(Method->parameters()[2]->getLocation(),
- diag::note_objc_literal_method_param)
- << 2 << CountType
- << "integral";
- return ExprError();
- }
- // We've found a good +dictionaryWithObjects:keys:count: method; save it!
- DictionaryWithObjectsMethod = Method;
- }
- QualType ValuesT = DictionaryWithObjectsMethod->parameters()[0]->getType();
- QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType();
- QualType KeysT = DictionaryWithObjectsMethod->parameters()[1]->getType();
- QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType();
- // Check that each of the keys and values provided is valid in a collection
- // literal, performing conversions as necessary.
- bool HasPackExpansions = false;
- for (ObjCDictionaryElement &Element : Elements) {
- // Check the key.
- ExprResult Key = CheckObjCCollectionLiteralElement(*this, Element.Key,
- KeyT);
- if (Key.isInvalid())
- return ExprError();
- // Check the value.
- ExprResult Value
- = CheckObjCCollectionLiteralElement(*this, Element.Value, ValueT);
- if (Value.isInvalid())
- return ExprError();
- Element.Key = Key.get();
- Element.Value = Value.get();
- if (Element.EllipsisLoc.isInvalid())
- continue;
- if (!Element.Key->containsUnexpandedParameterPack() &&
- !Element.Value->containsUnexpandedParameterPack()) {
- Diag(Element.EllipsisLoc,
- diag::err_pack_expansion_without_parameter_packs)
- << SourceRange(Element.Key->getBeginLoc(),
- Element.Value->getEndLoc());
- return ExprError();
- }
- HasPackExpansions = true;
- }
- QualType Ty = Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(NSDictionaryDecl));
- auto *Literal =
- ObjCDictionaryLiteral::Create(Context, Elements, HasPackExpansions, Ty,
- DictionaryWithObjectsMethod, SR);
- CheckObjCDictionaryLiteralDuplicateKeys(*this, Literal);
- return MaybeBindToTemporary(Literal);
- }
- ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
- TypeSourceInfo *EncodedTypeInfo,
- SourceLocation RParenLoc) {
- QualType EncodedType = EncodedTypeInfo->getType();
- QualType StrTy;
- if (EncodedType->isDependentType())
- StrTy = Context.DependentTy;
- else {
- if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled.
- !EncodedType->isVoidType()) // void is handled too.
- if (RequireCompleteType(AtLoc, EncodedType,
- diag::err_incomplete_type_objc_at_encode,
- EncodedTypeInfo->getTypeLoc()))
- return ExprError();
- std::string Str;
- QualType NotEncodedT;
- Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT);
- if (!NotEncodedT.isNull())
- Diag(AtLoc, diag::warn_incomplete_encoded_type)
- << EncodedType << NotEncodedT;
- // The type of @encode is the same as the type of the corresponding string,
- // which is an array type.
- StrTy = Context.getStringLiteralArrayType(Context.CharTy, Str.size());
- }
- return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc);
- }
- ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
- SourceLocation EncodeLoc,
- SourceLocation LParenLoc,
- ParsedType ty,
- SourceLocation RParenLoc) {
- // FIXME: Preserve type source info ?
- TypeSourceInfo *TInfo;
- QualType EncodedType = GetTypeFromParser(ty, &TInfo);
- if (!TInfo)
- TInfo = Context.getTrivialTypeSourceInfo(EncodedType,
- getLocForEndOfToken(LParenLoc));
- return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
- }
- static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
- SourceLocation AtLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc,
- ObjCMethodDecl *Method,
- ObjCMethodList &MethList) {
- ObjCMethodList *M = &MethList;
- bool Warned = false;
- for (M = M->getNext(); M; M=M->getNext()) {
- ObjCMethodDecl *MatchingMethodDecl = M->getMethod();
- if (MatchingMethodDecl == Method ||
- isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) ||
- MatchingMethodDecl->getSelector() != Method->getSelector())
- continue;
- if (!S.MatchTwoMethodDeclarations(Method,
- MatchingMethodDecl, Sema::MMS_loose)) {
- if (!Warned) {
- Warned = true;
- S.Diag(AtLoc, diag::warn_multiple_selectors)
- << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(")
- << FixItHint::CreateInsertion(RParenLoc, ")");
- S.Diag(Method->getLocation(), diag::note_method_declared_at)
- << Method->getDeclName();
- }
- S.Diag(MatchingMethodDecl->getLocation(), diag::note_method_declared_at)
- << MatchingMethodDecl->getDeclName();
- }
- }
- return Warned;
- }
- static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
- ObjCMethodDecl *Method,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc,
- bool WarnMultipleSelectors) {
- if (!WarnMultipleSelectors ||
- S.Diags.isIgnored(diag::warn_multiple_selectors, SourceLocation()))
- return;
- bool Warned = false;
- for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
- e = S.MethodPool.end(); b != e; b++) {
- // first, instance methods
- ObjCMethodList &InstMethList = b->second.first;
- if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
- Method, InstMethList))
- Warned = true;
- // second, class methods
- ObjCMethodList &ClsMethList = b->second.second;
- if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
- Method, ClsMethList) || Warned)
- return;
- }
- }
- static ObjCMethodDecl *LookupDirectMethodInMethodList(Sema &S, Selector Sel,
- ObjCMethodList &MethList,
- bool &onlyDirect,
- bool &anyDirect) {
- (void)Sel;
- ObjCMethodList *M = &MethList;
- ObjCMethodDecl *DirectMethod = nullptr;
- for (; M; M = M->getNext()) {
- ObjCMethodDecl *Method = M->getMethod();
- if (!Method)
- continue;
- assert(Method->getSelector() == Sel && "Method with wrong selector in method list");
- if (Method->isDirectMethod()) {
- anyDirect = true;
- DirectMethod = Method;
- } else
- onlyDirect = false;
- }
- return DirectMethod;
- }
- // Search the global pool for (potentially) direct methods matching the given
- // selector. If a non-direct method is found, set \param onlyDirect to false. If
- // a direct method is found, set \param anyDirect to true. Returns a direct
- // method, if any.
- static ObjCMethodDecl *LookupDirectMethodInGlobalPool(Sema &S, Selector Sel,
- bool &onlyDirect,
- bool &anyDirect) {
- auto Iter = S.MethodPool.find(Sel);
- if (Iter == S.MethodPool.end())
- return nullptr;
- ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList(
- S, Sel, Iter->second.first, onlyDirect, anyDirect);
- ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList(
- S, Sel, Iter->second.second, onlyDirect, anyDirect);
- return DirectInstance ? DirectInstance : DirectClass;
- }
- static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) {
- auto *CurMD = S.getCurMethodDecl();
- if (!CurMD)
- return nullptr;
- ObjCInterfaceDecl *IFace = CurMD->getClassInterface();
- // The language enforce that only one direct method is present in a given
- // class, so we just need to find one method in the current class to know
- // whether Sel is potentially direct in this context.
- if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true))
- return MD;
- if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/true))
- return MD;
- if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false))
- return MD;
- if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/false))
- return MD;
- return nullptr;
- }
- ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
- SourceLocation AtLoc,
- SourceLocation SelLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc,
- bool WarnMultipleSelectors) {
- ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc));
- if (!Method)
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc));
- if (!Method) {
- if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) {
- Selector MatchedSel = OM->getSelector();
- SourceRange SelectorRange(LParenLoc.getLocWithOffset(1),
- RParenLoc.getLocWithOffset(-1));
- Diag(SelLoc, diag::warn_undeclared_selector_with_typo)
- << Sel << MatchedSel
- << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
- } else
- Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
- } else {
- DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
- WarnMultipleSelectors);
- bool onlyDirect = true;
- bool anyDirect = false;
- ObjCMethodDecl *GlobalDirectMethod =
- LookupDirectMethodInGlobalPool(*this, Sel, onlyDirect, anyDirect);
- if (onlyDirect) {
- Diag(AtLoc, diag::err_direct_selector_expression)
- << Method->getSelector();
- Diag(Method->getLocation(), diag::note_direct_method_declared_at)
- << Method->getDeclName();
- } else if (anyDirect) {
- // If we saw any direct methods, see if we see a direct member of the
- // current class. If so, the @selector will likely be used to refer to
- // this direct method.
- ObjCMethodDecl *LikelyTargetMethod = findMethodInCurrentClass(*this, Sel);
- if (LikelyTargetMethod && LikelyTargetMethod->isDirectMethod()) {
- Diag(AtLoc, diag::warn_potentially_direct_selector_expression) << Sel;
- Diag(LikelyTargetMethod->getLocation(),
- diag::note_direct_method_declared_at)
- << LikelyTargetMethod->getDeclName();
- } else if (!LikelyTargetMethod) {
- // Otherwise, emit the "strict" variant of this diagnostic, unless
- // LikelyTargetMethod is non-direct.
- Diag(AtLoc, diag::warn_strict_potentially_direct_selector_expression)
- << Sel;
- Diag(GlobalDirectMethod->getLocation(),
- diag::note_direct_method_declared_at)
- << GlobalDirectMethod->getDeclName();
- }
- }
- }
- if (Method &&
- Method->getImplementationControl() != ObjCMethodDecl::Optional &&
- !getSourceManager().isInSystemHeader(Method->getLocation()))
- ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
- // In ARC, forbid the user from using @selector for
- // retain/release/autorelease/dealloc/retainCount.
- if (getLangOpts().ObjCAutoRefCount) {
- switch (Sel.getMethodFamily()) {
- case OMF_retain:
- case OMF_release:
- case OMF_autorelease:
- case OMF_retainCount:
- case OMF_dealloc:
- Diag(AtLoc, diag::err_arc_illegal_selector) <<
- Sel << SourceRange(LParenLoc, RParenLoc);
- break;
- case OMF_None:
- case OMF_alloc:
- case OMF_copy:
- case OMF_finalize:
- case OMF_init:
- case OMF_mutableCopy:
- case OMF_new:
- case OMF_self:
- case OMF_initialize:
- case OMF_performSelector:
- break;
- }
- }
- QualType Ty = Context.getObjCSelType();
- return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
- }
- ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
- SourceLocation AtLoc,
- SourceLocation ProtoLoc,
- SourceLocation LParenLoc,
- SourceLocation ProtoIdLoc,
- SourceLocation RParenLoc) {
- ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoIdLoc);
- if (!PDecl) {
- Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
- return true;
- }
- if (PDecl->isNonRuntimeProtocol())
- Diag(ProtoLoc, diag::err_objc_non_runtime_protocol_in_protocol_expr)
- << PDecl;
- if (!PDecl->hasDefinition()) {
- Diag(ProtoLoc, diag::err_atprotocol_protocol) << PDecl;
- Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
- } else {
- PDecl = PDecl->getDefinition();
- }
- QualType Ty = Context.getObjCProtoType();
- if (Ty.isNull())
- return true;
- Ty = Context.getObjCObjectPointerType(Ty);
- return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, ProtoIdLoc, RParenLoc);
- }
- /// Try to capture an implicit reference to 'self'.
- ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) {
- DeclContext *DC = getFunctionLevelDeclContext();
- // If we're not in an ObjC method, error out. Note that, unlike the
- // C++ case, we don't require an instance method --- class methods
- // still have a 'self', and we really do still need to capture it!
- ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC);
- if (!method)
- return nullptr;
- tryCaptureVariable(method->getSelfDecl(), Loc);
- return method;
- }
- static QualType stripObjCInstanceType(ASTContext &Context, QualType T) {
- QualType origType = T;
- if (auto nullability = AttributedType::stripOuterNullability(T)) {
- if (T == Context.getObjCInstanceType()) {
- return Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*nullability),
- Context.getObjCIdType(),
- Context.getObjCIdType());
- }
- return origType;
- }
- if (T == Context.getObjCInstanceType())
- return Context.getObjCIdType();
- return origType;
- }
- /// Determine the result type of a message send based on the receiver type,
- /// method, and the kind of message send.
- ///
- /// This is the "base" result type, which will still need to be adjusted
- /// to account for nullability.
- static QualType getBaseMessageSendResultType(Sema &S,
- QualType ReceiverType,
- ObjCMethodDecl *Method,
- bool isClassMessage,
- bool isSuperMessage) {
- assert(Method && "Must have a method");
- if (!Method->hasRelatedResultType())
- return Method->getSendResultType(ReceiverType);
- ASTContext &Context = S.Context;
- // Local function that transfers the nullability of the method's
- // result type to the returned result.
- auto transferNullability = [&](QualType type) -> QualType {
- // If the method's result type has nullability, extract it.
- if (auto nullability =
- Method->getSendResultType(ReceiverType)->getNullability()) {
- // Strip off any outer nullability sugar from the provided type.
- (void)AttributedType::stripOuterNullability(type);
- // Form a new attributed type using the method result type's nullability.
- return Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*nullability),
- type,
- type);
- }
- return type;
- };
- // If a method has a related return type:
- // - if the method found is an instance method, but the message send
- // was a class message send, T is the declared return type of the method
- // found
- if (Method->isInstanceMethod() && isClassMessage)
- return stripObjCInstanceType(Context,
- Method->getSendResultType(ReceiverType));
- // - if the receiver is super, T is a pointer to the class of the
- // enclosing method definition
- if (isSuperMessage) {
- if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl())
- if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) {
- return transferNullability(
- Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(Class)));
- }
- }
- // - if the receiver is the name of a class U, T is a pointer to U
- if (ReceiverType->getAsObjCInterfaceType())
- return transferNullability(Context.getObjCObjectPointerType(ReceiverType));
- // - if the receiver is of type Class or qualified Class type,
- // T is the declared return type of the method.
- if (ReceiverType->isObjCClassType() ||
- ReceiverType->isObjCQualifiedClassType())
- return stripObjCInstanceType(Context,
- Method->getSendResultType(ReceiverType));
- // - if the receiver is id, qualified id, Class, or qualified Class, T
- // is the receiver type, otherwise
- // - T is the type of the receiver expression.
- return transferNullability(ReceiverType);
- }
- QualType Sema::getMessageSendResultType(const Expr *Receiver,
- QualType ReceiverType,
- ObjCMethodDecl *Method,
- bool isClassMessage,
- bool isSuperMessage) {
- // Produce the result type.
- QualType resultType = getBaseMessageSendResultType(*this, ReceiverType,
- Method,
- isClassMessage,
- isSuperMessage);
- // If this is a class message, ignore the nullability of the receiver.
- if (isClassMessage) {
- // In a class method, class messages to 'self' that return instancetype can
- // be typed as the current class. We can safely do this in ARC because self
- // can't be reassigned, and we do it unsafely outside of ARC because in
- // practice people never reassign self in class methods and there's some
- // virtue in not being aggressively pedantic.
- if (Receiver && Receiver->isObjCSelfExpr()) {
- assert(ReceiverType->isObjCClassType() && "expected a Class self");
- QualType T = Method->getSendResultType(ReceiverType);
- AttributedType::stripOuterNullability(T);
- if (T == Context.getObjCInstanceType()) {
- const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(
- cast<ImplicitParamDecl>(
- cast<DeclRefExpr>(Receiver->IgnoreParenImpCasts())->getDecl())
- ->getDeclContext());
- assert(MD->isClassMethod() && "expected a class method");
- QualType NewResultType = Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(MD->getClassInterface()));
- if (auto Nullability = resultType->getNullability())
- NewResultType = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*Nullability),
- NewResultType, NewResultType);
- return NewResultType;
- }
- }
- return resultType;
- }
- // There is nothing left to do if the result type cannot have a nullability
- // specifier.
- if (!resultType->canHaveNullability())
- return resultType;
- // Map the nullability of the result into a table index.
- unsigned receiverNullabilityIdx = 0;
- if (std::optional<NullabilityKind> nullability =
- ReceiverType->getNullability()) {
- if (*nullability == NullabilityKind::NullableResult)
- nullability = NullabilityKind::Nullable;
- receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
- }
- unsigned resultNullabilityIdx = 0;
- if (std::optional<NullabilityKind> nullability =
- resultType->getNullability()) {
- if (*nullability == NullabilityKind::NullableResult)
- nullability = NullabilityKind::Nullable;
- resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
- }
- // The table of nullability mappings, indexed by the receiver's nullability
- // and then the result type's nullability.
- static const uint8_t None = 0;
- static const uint8_t NonNull = 1;
- static const uint8_t Nullable = 2;
- static const uint8_t Unspecified = 3;
- static const uint8_t nullabilityMap[4][4] = {
- // None NonNull Nullable Unspecified
- /* None */ { None, None, Nullable, None },
- /* NonNull */ { None, NonNull, Nullable, Unspecified },
- /* Nullable */ { Nullable, Nullable, Nullable, Nullable },
- /* Unspecified */ { None, Unspecified, Nullable, Unspecified }
- };
- unsigned newResultNullabilityIdx
- = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx];
- if (newResultNullabilityIdx == resultNullabilityIdx)
- return resultType;
- // Strip off the existing nullability. This removes as little type sugar as
- // possible.
- do {
- if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) {
- resultType = attributed->getModifiedType();
- } else {
- resultType = resultType.getDesugaredType(Context);
- }
- } while (resultType->getNullability());
- // Add nullability back if needed.
- if (newResultNullabilityIdx > 0) {
- auto newNullability
- = static_cast<NullabilityKind>(newResultNullabilityIdx-1);
- return Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(newNullability),
- resultType, resultType);
- }
- return resultType;
- }
- /// Look for an ObjC method whose result type exactly matches the given type.
- static const ObjCMethodDecl *
- findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
- QualType instancetype) {
- if (MD->getReturnType() == instancetype)
- return MD;
- // For these purposes, a method in an @implementation overrides a
- // declaration in the @interface.
- if (const ObjCImplDecl *impl =
- dyn_cast<ObjCImplDecl>(MD->getDeclContext())) {
- const ObjCContainerDecl *iface;
- if (const ObjCCategoryImplDecl *catImpl =
- dyn_cast<ObjCCategoryImplDecl>(impl)) {
- iface = catImpl->getCategoryDecl();
- } else {
- iface = impl->getClassInterface();
- }
- const ObjCMethodDecl *ifaceMD =
- iface->getMethod(MD->getSelector(), MD->isInstanceMethod());
- if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype);
- }
- SmallVector<const ObjCMethodDecl *, 4> overrides;
- MD->getOverriddenMethods(overrides);
- for (unsigned i = 0, e = overrides.size(); i != e; ++i) {
- if (const ObjCMethodDecl *result =
- findExplicitInstancetypeDeclarer(overrides[i], instancetype))
- return result;
- }
- return nullptr;
- }
- void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
- // Only complain if we're in an ObjC method and the required return
- // type doesn't match the method's declared return type.
- ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext);
- if (!MD || !MD->hasRelatedResultType() ||
- Context.hasSameUnqualifiedType(destType, MD->getReturnType()))
- return;
- // Look for a method overridden by this method which explicitly uses
- // 'instancetype'.
- if (const ObjCMethodDecl *overridden =
- findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
- SourceRange range = overridden->getReturnTypeSourceRange();
- SourceLocation loc = range.getBegin();
- if (loc.isInvalid())
- loc = overridden->getLocation();
- Diag(loc, diag::note_related_result_type_explicit)
- << /*current method*/ 1 << range;
- return;
- }
- // Otherwise, if we have an interesting method family, note that.
- // This should always trigger if the above didn't.
- if (ObjCMethodFamily family = MD->getMethodFamily())
- Diag(MD->getLocation(), diag::note_related_result_type_family)
- << /*current method*/ 1
- << family;
- }
- void Sema::EmitRelatedResultTypeNote(const Expr *E) {
- E = E->IgnoreParenImpCasts();
- const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
- if (!MsgSend)
- return;
- const ObjCMethodDecl *Method = MsgSend->getMethodDecl();
- if (!Method)
- return;
- if (!Method->hasRelatedResultType())
- return;
- if (Context.hasSameUnqualifiedType(
- Method->getReturnType().getNonReferenceType(), MsgSend->getType()))
- return;
- if (!Context.hasSameUnqualifiedType(Method->getReturnType(),
- Context.getObjCInstanceType()))
- return;
- Diag(Method->getLocation(), diag::note_related_result_type_inferred)
- << Method->isInstanceMethod() << Method->getSelector()
- << MsgSend->getType();
- }
- bool Sema::CheckMessageArgumentTypes(
- const Expr *Receiver, QualType ReceiverType, MultiExprArg Args,
- Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method,
- bool isClassMessage, bool isSuperMessage, SourceLocation lbrac,
- SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType,
- ExprValueKind &VK) {
- SourceLocation SelLoc;
- if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
- SelLoc = SelectorLocs.front();
- else
- SelLoc = lbrac;
- if (!Method) {
- // Apply default argument promotion as for (C99 6.5.2.2p6).
- for (unsigned i = 0, e = Args.size(); i != e; i++) {
- if (Args[i]->isTypeDependent())
- continue;
- ExprResult result;
- if (getLangOpts().DebuggerSupport) {
- QualType paramTy; // ignored
- result = checkUnknownAnyArg(SelLoc, Args[i], paramTy);
- } else {
- result = DefaultArgumentPromotion(Args[i]);
- }
- if (result.isInvalid())
- return true;
- Args[i] = result.get();
- }
- unsigned DiagID;
- if (getLangOpts().ObjCAutoRefCount)
- DiagID = diag::err_arc_method_not_found;
- else
- DiagID = isClassMessage ? diag::warn_class_method_not_found
- : diag::warn_inst_method_not_found;
- if (!getLangOpts().DebuggerSupport) {
- const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType);
- if (OMD && !OMD->isInvalidDecl()) {
- if (getLangOpts().ObjCAutoRefCount)
- DiagID = diag::err_method_not_found_with_typo;
- else
- DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo
- : diag::warn_instance_method_not_found_with_typo;
- Selector MatchedSel = OMD->getSelector();
- SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back());
- if (MatchedSel.isUnarySelector())
- Diag(SelLoc, DiagID)
- << Sel<< isClassMessage << MatchedSel
- << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
- else
- Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel;
- }
- else
- Diag(SelLoc, DiagID)
- << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
- SelectorLocs.back());
- // Find the class to which we are sending this message.
- if (auto *ObjPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
- if (ObjCInterfaceDecl *ThisClass = ObjPT->getInterfaceDecl()) {
- Diag(ThisClass->getLocation(), diag::note_receiver_class_declared);
- if (!RecRange.isInvalid())
- if (ThisClass->lookupClassMethod(Sel))
- Diag(RecRange.getBegin(), diag::note_receiver_expr_here)
- << FixItHint::CreateReplacement(RecRange,
- ThisClass->getNameAsString());
- }
- }
- }
- // In debuggers, we want to use __unknown_anytype for these
- // results so that clients can cast them.
- if (getLangOpts().DebuggerSupport) {
- ReturnType = Context.UnknownAnyTy;
- } else {
- ReturnType = Context.getObjCIdType();
- }
- VK = VK_PRValue;
- return false;
- }
- ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method,
- isClassMessage, isSuperMessage);
- VK = Expr::getValueKindForType(Method->getReturnType());
- unsigned NumNamedArgs = Sel.getNumArgs();
- // Method might have more arguments than selector indicates. This is due
- // to addition of c-style arguments in method.
- if (Method->param_size() > Sel.getNumArgs())
- NumNamedArgs = Method->param_size();
- // FIXME. This need be cleaned up.
- if (Args.size() < NumNamedArgs) {
- Diag(SelLoc, diag::err_typecheck_call_too_few_args)
- << 2 << NumNamedArgs << static_cast<unsigned>(Args.size());
- return false;
- }
- // Compute the set of type arguments to be substituted into each parameter
- // type.
- std::optional<ArrayRef<QualType>> typeArgs =
- ReceiverType->getObjCSubstitutions(Method->getDeclContext());
- bool IsError = false;
- for (unsigned i = 0; i < NumNamedArgs; i++) {
- // We can't do any type-checking on a type-dependent argument.
- if (Args[i]->isTypeDependent())
- continue;
- Expr *argExpr = Args[i];
- ParmVarDecl *param = Method->parameters()[i];
- assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
- if (param->hasAttr<NoEscapeAttr>() &&
- param->getType()->isBlockPointerType())
- if (auto *BE = dyn_cast<BlockExpr>(
- argExpr->IgnoreParenNoopCasts(Context)))
- BE->getBlockDecl()->setDoesNotEscape();
- // Strip the unbridged-cast placeholder expression off unless it's
- // a consumed argument.
- if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
- !param->hasAttr<CFConsumedAttr>())
- argExpr = stripARCUnbridgedCast(argExpr);
- // If the parameter is __unknown_anytype, infer its type
- // from the argument.
- if (param->getType() == Context.UnknownAnyTy) {
- QualType paramType;
- ExprResult argE = checkUnknownAnyArg(SelLoc, argExpr, paramType);
- if (argE.isInvalid()) {
- IsError = true;
- } else {
- Args[i] = argE.get();
- // Update the parameter type in-place.
- param->setType(paramType);
- }
- continue;
- }
- QualType origParamType = param->getType();
- QualType paramType = param->getType();
- if (typeArgs)
- paramType = paramType.substObjCTypeArgs(
- Context,
- *typeArgs,
- ObjCSubstitutionContext::Parameter);
- if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
- paramType,
- diag::err_call_incomplete_argument, argExpr))
- return true;
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(Context, param, paramType);
- ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr);
- if (ArgE.isInvalid())
- IsError = true;
- else {
- Args[i] = ArgE.getAs<Expr>();
- // If we are type-erasing a block to a block-compatible
- // Objective-C pointer type, we may need to extend the lifetime
- // of the block object.
- if (typeArgs && Args[i]->isPRValue() && paramType->isBlockPointerType() &&
- Args[i]->getType()->isBlockPointerType() &&
- origParamType->isObjCObjectPointerType()) {
- ExprResult arg = Args[i];
- maybeExtendBlockObject(arg);
- Args[i] = arg.get();
- }
- }
- }
- // Promote additional arguments to variadic methods.
- if (Method->isVariadic()) {
- for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
- if (Args[i]->isTypeDependent())
- continue;
- ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
- nullptr);
- IsError |= Arg.isInvalid();
- Args[i] = Arg.get();
- }
- } else {
- // Check for extra arguments to non-variadic methods.
- if (Args.size() != NumNamedArgs) {
- Diag(Args[NumNamedArgs]->getBeginLoc(),
- diag::err_typecheck_call_too_many_args)
- << 2 /*method*/ << NumNamedArgs << static_cast<unsigned>(Args.size())
- << Method->getSourceRange()
- << SourceRange(Args[NumNamedArgs]->getBeginLoc(),
- Args.back()->getEndLoc());
- }
- }
- DiagnoseSentinelCalls(Method, SelLoc, Args);
- // Do additional checkings on method.
- IsError |=
- CheckObjCMethodCall(Method, SelLoc, ArrayRef(Args.data(), Args.size()));
- return IsError;
- }
- bool Sema::isSelfExpr(Expr *RExpr) {
- // 'self' is objc 'self' in an objc method only.
- ObjCMethodDecl *Method =
- dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
- return isSelfExpr(RExpr, Method);
- }
- bool Sema::isSelfExpr(Expr *receiver, const ObjCMethodDecl *method) {
- if (!method) return false;
- receiver = receiver->IgnoreParenLValueCasts();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
- if (DRE->getDecl() == method->getSelfDecl())
- return true;
- return false;
- }
- /// LookupMethodInType - Look up a method in an ObjCObjectType.
- ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
- bool isInstance) {
- const ObjCObjectType *objType = type->castAs<ObjCObjectType>();
- if (ObjCInterfaceDecl *iface = objType->getInterface()) {
- // Look it up in the main interface (and categories, etc.)
- if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance))
- return method;
- // Okay, look for "private" methods declared in any
- // @implementations we've seen.
- if (ObjCMethodDecl *method = iface->lookupPrivateMethod(sel, isInstance))
- return method;
- }
- // Check qualifiers.
- for (const auto *I : objType->quals())
- if (ObjCMethodDecl *method = I->lookupMethod(sel, isInstance))
- return method;
- return nullptr;
- }
- /// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
- /// list of a qualified objective pointer type.
- ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
- const ObjCObjectPointerType *OPT,
- bool Instance)
- {
- ObjCMethodDecl *MD = nullptr;
- for (const auto *PROTO : OPT->quals()) {
- if ((MD = PROTO->lookupMethod(Sel, Instance))) {
- return MD;
- }
- }
- return nullptr;
- }
- /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
- /// objective C interface. This is a property reference expression.
- ExprResult Sema::
- HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
- Expr *BaseExpr, SourceLocation OpLoc,
- DeclarationName MemberName,
- SourceLocation MemberLoc,
- SourceLocation SuperLoc, QualType SuperType,
- bool Super) {
- const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
- ObjCInterfaceDecl *IFace = IFaceT->getDecl();
- if (!MemberName.isIdentifier()) {
- Diag(MemberLoc, diag::err_invalid_property_name)
- << MemberName << QualType(OPT, 0);
- return ExprError();
- }
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- SourceRange BaseRange = Super? SourceRange(SuperLoc)
- : BaseExpr->getSourceRange();
- if (RequireCompleteType(MemberLoc, OPT->getPointeeType(),
- diag::err_property_not_found_forward_class,
- MemberName, BaseRange))
- return ExprError();
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(
- Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
- if (Super)
- return new (Context)
- ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
- else
- return new (Context)
- ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, MemberLoc, BaseExpr);
- }
- // Check protocols on qualified interfaces.
- for (const auto *I : OPT->quals())
- if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
- Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
- if (Super)
- return new (Context) ObjCPropertyRefExpr(
- PD, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, MemberLoc,
- SuperLoc, SuperType);
- else
- return new (Context)
- ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, MemberLoc, BaseExpr);
- }
- // If that failed, look for an "implicit" property by seeing if the nullary
- // selector is implemented.
- // FIXME: The logic for looking up nullary and unary selectors should be
- // shared with the code in ActOnInstanceMessage.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- // May be found in property's qualified list.
- if (!Getter)
- Getter = LookupMethodInQualifiedType(Sel, OPT, true);
- // If this reference is in an @implementation, check for 'private' methods.
- if (!Getter)
- Getter = IFace->lookupPrivateMethod(Sel);
- if (Getter) {
- // Check if we can reference this property.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- }
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
- // May be found in property's qualified list.
- if (!Setter)
- Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateMethod(SetterSel);
- }
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
- // Special warning if member name used in a property-dot for a setter accessor
- // does not use a property with same name; e.g. obj.X = ... for a property with
- // name 'x'.
- if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() &&
- !IFace->FindPropertyDeclaration(
- Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
- if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
- // Do not warn if user is using property-dot syntax to make call to
- // user named setter.
- if (!(PDecl->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_setter))
- Diag(MemberLoc,
- diag::warn_property_access_suggest)
- << MemberName << QualType(OPT, 0) << PDecl->getName()
- << FixItHint::CreateReplacement(MemberLoc, PDecl->getName());
- }
- }
- if (Getter || Setter) {
- if (Super)
- return new (Context)
- ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
- else
- return new (Context)
- ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, MemberLoc, BaseExpr);
- }
- // Attempt to correct for typos in property names.
- DeclFilterCCC<ObjCPropertyDecl> CCC{};
- if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName,
- nullptr, nullptr, CCC, CTK_ErrorRecovery, IFace, false, OPT)) {
- DeclarationName TypoResult = Corrected.getCorrection();
- if (TypoResult.isIdentifier() &&
- TypoResult.getAsIdentifierInfo() == Member) {
- // There is no need to try the correction if it is the same.
- NamedDecl *ChosenDecl =
- Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl();
- if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl))
- if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) {
- // This is a class property, we should not use the instance to
- // access it.
- Diag(MemberLoc, diag::err_class_property_found) << MemberName
- << OPT->getInterfaceDecl()->getName()
- << FixItHint::CreateReplacement(BaseExpr->getSourceRange(),
- OPT->getInterfaceDecl()->getName());
- return ExprError();
- }
- } else {
- diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
- << MemberName << QualType(OPT, 0));
- return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
- TypoResult, MemberLoc,
- SuperLoc, SuperType, Super);
- }
- }
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *Ivar =
- IFace->lookupInstanceVariable(Member, ClassDeclared)) {
- QualType T = Ivar->getType();
- if (const ObjCObjectPointerType * OBJPT =
- T->getAsObjCInterfacePointerType()) {
- if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(),
- diag::err_property_not_as_forward_class,
- MemberName, BaseExpr))
- return ExprError();
- }
- Diag(MemberLoc,
- diag::err_ivar_access_using_property_syntax_suggest)
- << MemberName << QualType(OPT, 0) << Ivar->getDeclName()
- << FixItHint::CreateReplacement(OpLoc, "->");
- return ExprError();
- }
- Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << QualType(OPT, 0);
- if (Setter)
- Diag(Setter->getLocation(), diag::note_getter_unavailable)
- << MemberName << BaseExpr->getSourceRange();
- return ExprError();
- }
- ExprResult Sema::
- ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation receiverNameLoc,
- SourceLocation propertyNameLoc) {
- IdentifierInfo *receiverNamePtr = &receiverName;
- ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
- receiverNameLoc);
- QualType SuperType;
- if (!IFace) {
- // If the "receiver" is 'super' in a method, handle it as an expression-like
- // property reference.
- if (receiverNamePtr->isStr("super")) {
- if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
- if (auto classDecl = CurMethod->getClassInterface()) {
- SuperType = QualType(classDecl->getSuperClassType(), 0);
- if (CurMethod->isInstanceMethod()) {
- if (SuperType.isNull()) {
- // The current class does not have a superclass.
- Diag(receiverNameLoc, diag::err_root_class_cannot_use_super)
- << CurMethod->getClassInterface()->getIdentifier();
- return ExprError();
- }
- QualType T = Context.getObjCObjectPointerType(SuperType);
- return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(),
- /*BaseExpr*/nullptr,
- SourceLocation()/*OpLoc*/,
- &propertyName,
- propertyNameLoc,
- receiverNameLoc, T, true);
- }
- // Otherwise, if this is a class method, try dispatching to our
- // superclass.
- IFace = CurMethod->getClassInterface()->getSuperClass();
- }
- }
- }
- if (!IFace) {
- Diag(receiverNameLoc, diag::err_expected_either) << tok::identifier
- << tok::l_paren;
- return ExprError();
- }
- }
- Selector GetterSel;
- Selector SetterSel;
- if (auto PD = IFace->FindPropertyDeclaration(
- &propertyName, ObjCPropertyQueryKind::OBJC_PR_query_class)) {
- GetterSel = PD->getGetterName();
- SetterSel = PD->getSetterName();
- } else {
- GetterSel = PP.getSelectorTable().getNullarySelector(&propertyName);
- SetterSel = SelectorTable::constructSetterSelector(
- PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName);
- }
- // Search for a declared property first.
- ObjCMethodDecl *Getter = IFace->lookupClassMethod(GetterSel);
- // If this reference is in an @implementation, check for 'private' methods.
- if (!Getter)
- Getter = IFace->lookupPrivateClassMethod(GetterSel);
- if (Getter) {
- // FIXME: refactor/share with ActOnMemberReference().
- // Check if we can reference this property.
- if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
- return ExprError();
- }
- // Look for the matching setter, in case it is needed.
- ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateClassMethod(SetterSel);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryClassMethod(SetterSel);
- if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
- return ExprError();
- if (Getter || Setter) {
- if (!SuperType.isNull())
- return new (Context)
- ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
- OK_ObjCProperty, propertyNameLoc, receiverNameLoc,
- SuperType);
- return new (Context) ObjCPropertyRefExpr(
- Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty,
- propertyNameLoc, receiverNameLoc, IFace);
- }
- return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
- << &propertyName << Context.getObjCInterfaceType(IFace));
- }
- namespace {
- class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback {
- public:
- ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) {
- // Determine whether "super" is acceptable in the current context.
- if (Method && Method->getClassInterface())
- WantObjCSuper = Method->getClassInterface()->getSuperClass();
- }
- bool ValidateCandidate(const TypoCorrection &candidate) override {
- return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
- candidate.isKeyword("super");
- }
- std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return std::make_unique<ObjCInterfaceOrSuperCCC>(*this);
- }
- };
- } // end anonymous namespace
- Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
- IdentifierInfo *Name,
- SourceLocation NameLoc,
- bool IsSuper,
- bool HasTrailingDot,
- ParsedType &ReceiverType) {
- ReceiverType = nullptr;
- // If the identifier is "super" and there is no trailing dot, we're
- // messaging super. If the identifier is "super" and there is a
- // trailing dot, it's an instance message.
- if (IsSuper && S->isInObjcMethodScope())
- return HasTrailingDot? ObjCInstanceMessage : ObjCSuperMessage;
- LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
- LookupName(Result, S);
- switch (Result.getResultKind()) {
- case LookupResult::NotFound:
- // Normal name lookup didn't find anything. If we're in an
- // Objective-C method, look for ivars. If we find one, we're done!
- // FIXME: This is a hack. Ivar lookup should be part of normal
- // lookup.
- if (ObjCMethodDecl *Method = getCurMethodDecl()) {
- if (!Method->getClassInterface()) {
- // Fall back: let the parser try to parse it as an instance message.
- return ObjCInstanceMessage;
- }
- ObjCInterfaceDecl *ClassDeclared;
- if (Method->getClassInterface()->lookupInstanceVariable(Name,
- ClassDeclared))
- return ObjCInstanceMessage;
- }
- // Break out; we'll perform typo correction below.
- break;
- case LookupResult::NotFoundInCurrentInstantiation:
- case LookupResult::FoundOverloaded:
- case LookupResult::FoundUnresolvedValue:
- case LookupResult::Ambiguous:
- Result.suppressDiagnostics();
- return ObjCInstanceMessage;
- case LookupResult::Found: {
- // If the identifier is a class or not, and there is a trailing dot,
- // it's an instance message.
- if (HasTrailingDot)
- return ObjCInstanceMessage;
- // We found something. If it's a type, then we have a class
- // message. Otherwise, it's an instance message.
- NamedDecl *ND = Result.getFoundDecl();
- QualType T;
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
- T = Context.getObjCInterfaceType(Class);
- else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) {
- T = Context.getTypeDeclType(Type);
- DiagnoseUseOfDecl(Type, NameLoc);
- }
- else
- return ObjCInstanceMessage;
- // We have a class message, and T is the type we're
- // messaging. Build source-location information for it.
- TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
- ReceiverType = CreateParsedType(T, TSInfo);
- return ObjCClassMessage;
- }
- }
- ObjCInterfaceOrSuperCCC CCC(getCurMethodDecl());
- if (TypoCorrection Corrected = CorrectTypo(
- Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, CCC,
- CTK_ErrorRecovery, nullptr, false, nullptr, false)) {
- if (Corrected.isKeyword()) {
- // If we've found the keyword "super" (the only keyword that would be
- // returned by CorrectTypo), this is a send to super.
- diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_receiver_suggest) << Name);
- return ObjCSuperMessage;
- } else if (ObjCInterfaceDecl *Class =
- Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
- // If we found a declaration, correct when it refers to an Objective-C
- // class.
- diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_receiver_suggest) << Name);
- QualType T = Context.getObjCInterfaceType(Class);
- TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
- ReceiverType = CreateParsedType(T, TSInfo);
- return ObjCClassMessage;
- }
- }
- // Fall back: let the parser try to parse it as an instance message.
- return ObjCInstanceMessage;
- }
- ExprResult Sema::ActOnSuperMessage(Scope *S,
- SourceLocation SuperLoc,
- Selector Sel,
- SourceLocation LBracLoc,
- ArrayRef<SourceLocation> SelectorLocs,
- SourceLocation RBracLoc,
- MultiExprArg Args) {
- // Determine whether we are inside a method or not.
- ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc);
- if (!Method) {
- Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
- return ExprError();
- }
- ObjCInterfaceDecl *Class = Method->getClassInterface();
- if (!Class) {
- Diag(SuperLoc, diag::err_no_super_class_message)
- << Method->getDeclName();
- return ExprError();
- }
- QualType SuperTy(Class->getSuperClassType(), 0);
- if (SuperTy.isNull()) {
- // The current class does not have a superclass.
- Diag(SuperLoc, diag::err_root_class_cannot_use_super)
- << Class->getIdentifier();
- return ExprError();
- }
- // We are in a method whose class has a superclass, so 'super'
- // is acting as a keyword.
- if (Method->getSelector() == Sel)
- getCurFunction()->ObjCShouldCallSuper = false;
- if (Method->isInstanceMethod()) {
- // Since we are in an instance method, this is an instance
- // message to the superclass instance.
- SuperTy = Context.getObjCObjectPointerType(SuperTy);
- return BuildInstanceMessage(nullptr, SuperTy, SuperLoc,
- Sel, /*Method=*/nullptr,
- LBracLoc, SelectorLocs, RBracLoc, Args);
- }
- // Since we are in a class method, this is a class message to
- // the superclass.
- return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr,
- SuperTy,
- SuperLoc, Sel, /*Method=*/nullptr,
- LBracLoc, SelectorLocs, RBracLoc, Args);
- }
- ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
- bool isSuperReceiver,
- SourceLocation Loc,
- Selector Sel,
- ObjCMethodDecl *Method,
- MultiExprArg Args) {
- TypeSourceInfo *receiverTypeInfo = nullptr;
- if (!ReceiverType.isNull())
- receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType);
- return BuildClassMessage(receiverTypeInfo, ReceiverType,
- /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(),
- Sel, Method, Loc, Loc, Loc, Args,
- /*isImplicit=*/true);
- }
- static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg,
- unsigned DiagID,
- bool (*refactor)(const ObjCMessageExpr *,
- const NSAPI &, edit::Commit &)) {
- SourceLocation MsgLoc = Msg->getExprLoc();
- if (S.Diags.isIgnored(DiagID, MsgLoc))
- return;
- SourceManager &SM = S.SourceMgr;
- edit::Commit ECommit(SM, S.LangOpts);
- if (refactor(Msg,*S.NSAPIObj, ECommit)) {
- auto Builder = S.Diag(MsgLoc, DiagID)
- << Msg->getSelector() << Msg->getSourceRange();
- // FIXME: Don't emit diagnostic at all if fixits are non-commitable.
- if (!ECommit.isCommitable())
- return;
- for (edit::Commit::edit_iterator
- I = ECommit.edit_begin(), E = ECommit.edit_end(); I != E; ++I) {
- const edit::Commit::Edit &Edit = *I;
- switch (Edit.Kind) {
- case edit::Commit::Act_Insert:
- Builder.AddFixItHint(FixItHint::CreateInsertion(Edit.OrigLoc,
- Edit.Text,
- Edit.BeforePrev));
- break;
- case edit::Commit::Act_InsertFromRange:
- Builder.AddFixItHint(
- FixItHint::CreateInsertionFromRange(Edit.OrigLoc,
- Edit.getInsertFromRange(SM),
- Edit.BeforePrev));
- break;
- case edit::Commit::Act_Remove:
- Builder.AddFixItHint(FixItHint::CreateRemoval(Edit.getFileRange(SM)));
- break;
- }
- }
- }
- }
- static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
- applyCocoaAPICheck(S, Msg, diag::warn_objc_redundant_literal_use,
- edit::rewriteObjCRedundantCallWithLiteral);
- }
- static void checkFoundationAPI(Sema &S, SourceLocation Loc,
- const ObjCMethodDecl *Method,
- ArrayRef<Expr *> Args, QualType ReceiverType,
- bool IsClassObjectCall) {
- // Check if this is a performSelector method that uses a selector that returns
- // a record or a vector type.
- if (Method->getSelector().getMethodFamily() != OMF_performSelector ||
- Args.empty())
- return;
- const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens());
- if (!SE)
- return;
- ObjCMethodDecl *ImpliedMethod;
- if (!IsClassObjectCall) {
- const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>();
- if (!OPT || !OPT->getInterfaceDecl())
- return;
- ImpliedMethod =
- OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector());
- if (!ImpliedMethod)
- ImpliedMethod =
- OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector());
- } else {
- const auto *IT = ReceiverType->getAs<ObjCInterfaceType>();
- if (!IT)
- return;
- ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector());
- if (!ImpliedMethod)
- ImpliedMethod =
- IT->getDecl()->lookupPrivateClassMethod(SE->getSelector());
- }
- if (!ImpliedMethod)
- return;
- QualType Ret = ImpliedMethod->getReturnType();
- if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) {
- S.Diag(Loc, diag::warn_objc_unsafe_perform_selector)
- << Method->getSelector()
- << (!Ret->isRecordType()
- ? /*Vector*/ 2
- : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0);
- S.Diag(ImpliedMethod->getBeginLoc(),
- diag::note_objc_unsafe_perform_selector_method_declared_here)
- << ImpliedMethod->getSelector() << Ret;
- }
- }
- /// Diagnose use of %s directive in an NSString which is being passed
- /// as formatting string to formatting method.
- static void
- DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S,
- ObjCMethodDecl *Method,
- Selector Sel,
- Expr **Args, unsigned NumArgs) {
- unsigned Idx = 0;
- bool Format = false;
- ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily();
- if (SFFamily == ObjCStringFormatFamily::SFF_NSString) {
- Idx = 0;
- Format = true;
- }
- else if (Method) {
- for (const auto *I : Method->specific_attrs<FormatAttr>()) {
- if (S.GetFormatNSStringIdx(I, Idx)) {
- Format = true;
- break;
- }
- }
- }
- if (!Format || NumArgs <= Idx)
- return;
- Expr *FormatExpr = Args[Idx];
- if (ObjCStringLiteral *OSL =
- dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
- StringLiteral *FormatString = OSL->getString();
- if (S.FormatStringHasSArg(FormatString)) {
- S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
- << "%s" << 0 << 0;
- if (Method)
- S.Diag(Method->getLocation(), diag::note_method_declared_at)
- << Method->getDeclName();
- }
- }
- }
- /// Build an Objective-C class message expression.
- ///
- /// This routine takes care of both normal class messages and
- /// class messages to the superclass.
- ///
- /// \param ReceiverTypeInfo Type source information that describes the
- /// receiver of this message. This may be NULL, in which case we are
- /// sending to the superclass and \p SuperLoc must be a valid source
- /// location.
- /// \param ReceiverType The type of the object receiving the
- /// message. When \p ReceiverTypeInfo is non-NULL, this is the same
- /// type as that refers to. For a superclass send, this is the type of
- /// the superclass.
- ///
- /// \param SuperLoc The location of the "super" keyword in a
- /// superclass message.
- ///
- /// \param Sel The selector to which the message is being sent.
- ///
- /// \param Method The method that this class message is invoking, if
- /// already known.
- ///
- /// \param LBracLoc The location of the opening square bracket ']'.
- ///
- /// \param RBracLoc The location of the closing square bracket ']'.
- ///
- /// \param ArgsIn The message arguments.
- ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
- QualType ReceiverType,
- SourceLocation SuperLoc,
- Selector Sel,
- ObjCMethodDecl *Method,
- SourceLocation LBracLoc,
- ArrayRef<SourceLocation> SelectorLocs,
- SourceLocation RBracLoc,
- MultiExprArg ArgsIn,
- bool isImplicit) {
- SourceLocation Loc = SuperLoc.isValid()? SuperLoc
- : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
- if (LBracLoc.isInvalid()) {
- Diag(Loc, diag::err_missing_open_square_message_send)
- << FixItHint::CreateInsertion(Loc, "[");
- LBracLoc = Loc;
- }
- ArrayRef<SourceLocation> SelectorSlotLocs;
- if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
- SelectorSlotLocs = SelectorLocs;
- else
- SelectorSlotLocs = Loc;
- SourceLocation SelLoc = SelectorSlotLocs.front();
- if (ReceiverType->isDependentType()) {
- // If the receiver type is dependent, we can't type-check anything
- // at this point. Build a dependent expression.
- unsigned NumArgs = ArgsIn.size();
- Expr **Args = ArgsIn.data();
- assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return ObjCMessageExpr::Create(Context, ReceiverType, VK_PRValue, LBracLoc,
- ReceiverTypeInfo, Sel, SelectorLocs,
- /*Method=*/nullptr, ArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
- }
- // Find the class to which we are sending this message.
- ObjCInterfaceDecl *Class = nullptr;
- const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
- if (!ClassType || !(Class = ClassType->getInterface())) {
- Diag(Loc, diag::err_invalid_receiver_class_message)
- << ReceiverType;
- return ExprError();
- }
- assert(Class && "We don't know which class we're messaging?");
- // objc++ diagnoses during typename annotation.
- if (!getLangOpts().CPlusPlus)
- (void)DiagnoseUseOfDecl(Class, SelectorSlotLocs);
- // Find the method we are messaging.
- if (!Method) {
- SourceRange TypeRange
- = SuperLoc.isValid()? SourceRange(SuperLoc)
- : ReceiverTypeInfo->getTypeLoc().getSourceRange();
- if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
- (getLangOpts().ObjCAutoRefCount
- ? diag::err_arc_receiver_forward_class
- : diag::warn_receiver_forward_class),
- TypeRange)) {
- // A forward class used in messaging is treated as a 'Class'
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (Method && !getLangOpts().ObjCAutoRefCount)
- Diag(Method->getLocation(), diag::note_method_sent_forward_class)
- << Method->getDeclName();
- }
- if (!Method)
- Method = Class->lookupClassMethod(Sel);
- // If we have an implementation in scope, check "private" methods.
- if (!Method)
- Method = Class->lookupPrivateClassMethod(Sel);
- if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs,
- nullptr, false, false, Class))
- return ExprError();
- }
- // Check the argument types and determine the result type.
- QualType ReturnType;
- ExprValueKind VK = VK_PRValue;
- unsigned NumArgs = ArgsIn.size();
- Expr **Args = ArgsIn.data();
- if (CheckMessageArgumentTypes(/*Receiver=*/nullptr, ReceiverType,
- MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
- Method, true, SuperLoc.isValid(), LBracLoc,
- RBracLoc, SourceRange(), ReturnType, VK))
- return ExprError();
- if (Method && !Method->getReturnType()->isVoidType() &&
- RequireCompleteType(LBracLoc, Method->getReturnType(),
- diag::err_illegal_message_expr_incomplete_type))
- return ExprError();
- if (Method && Method->isDirectMethod() && SuperLoc.isValid()) {
- Diag(SuperLoc, diag::err_messaging_super_with_direct_method)
- << FixItHint::CreateReplacement(
- SuperLoc, getLangOpts().ObjCAutoRefCount
- ? "self"
- : Method->getClassInterface()->getName());
- Diag(Method->getLocation(), diag::note_direct_method_declared_at)
- << Method->getDeclName();
- }
- // Warn about explicit call of +initialize on its own class. But not on 'super'.
- if (Method && Method->getMethodFamily() == OMF_initialize) {
- if (!SuperLoc.isValid()) {
- const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext());
- if (ID == Class) {
- Diag(Loc, diag::warn_direct_initialize_call);
- Diag(Method->getLocation(), diag::note_method_declared_at)
- << Method->getDeclName();
- }
- }
- else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- // [super initialize] is allowed only within an +initialize implementation
- if (CurMeth->getMethodFamily() != OMF_initialize) {
- Diag(Loc, diag::warn_direct_super_initialize_call);
- Diag(Method->getLocation(), diag::note_method_declared_at)
- << Method->getDeclName();
- Diag(CurMeth->getLocation(), diag::note_method_declared_at)
- << CurMeth->getDeclName();
- }
- }
- }
- DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
- // Construct the appropriate ObjCMessageExpr.
- ObjCMessageExpr *Result;
- if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(
- Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
- else {
- Result = ObjCMessageExpr::Create(
- Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLocs,
- Method, ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
- if (!isImplicit)
- checkCocoaAPI(*this, Result);
- }
- if (Method)
- checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
- ReceiverType, /*IsClassObjectCall=*/true);
- return MaybeBindToTemporary(Result);
- }
- // ActOnClassMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from Sel.getNumArgs().
- ExprResult Sema::ActOnClassMessage(Scope *S,
- ParsedType Receiver,
- Selector Sel,
- SourceLocation LBracLoc,
- ArrayRef<SourceLocation> SelectorLocs,
- SourceLocation RBracLoc,
- MultiExprArg Args) {
- TypeSourceInfo *ReceiverTypeInfo;
- QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo);
- if (ReceiverType.isNull())
- return ExprError();
- if (!ReceiverTypeInfo)
- ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
- return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
- /*SuperLoc=*/SourceLocation(), Sel,
- /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc,
- Args);
- }
- ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
- QualType ReceiverType,
- SourceLocation Loc,
- Selector Sel,
- ObjCMethodDecl *Method,
- MultiExprArg Args) {
- return BuildInstanceMessage(Receiver, ReceiverType,
- /*SuperLoc=*/!Receiver ? Loc : SourceLocation(),
- Sel, Method, Loc, Loc, Loc, Args,
- /*isImplicit=*/true);
- }
- static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) {
- if (!S.NSAPIObj)
- return false;
- const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext());
- if (!Protocol)
- return false;
- const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
- if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>(
- S.LookupSingleName(S.TUScope, II, Protocol->getBeginLoc(),
- Sema::LookupOrdinaryName))) {
- for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) {
- if (P->getCanonicalDecl() == Protocol->getCanonicalDecl())
- return true;
- }
- }
- return false;
- }
- /// Build an Objective-C instance message expression.
- ///
- /// This routine takes care of both normal instance messages and
- /// instance messages to the superclass instance.
- ///
- /// \param Receiver The expression that computes the object that will
- /// receive this message. This may be empty, in which case we are
- /// sending to the superclass instance and \p SuperLoc must be a valid
- /// source location.
- ///
- /// \param ReceiverType The (static) type of the object receiving the
- /// message. When a \p Receiver expression is provided, this is the
- /// same type as that expression. For a superclass instance send, this
- /// is a pointer to the type of the superclass.
- ///
- /// \param SuperLoc The location of the "super" keyword in a
- /// superclass instance message.
- ///
- /// \param Sel The selector to which the message is being sent.
- ///
- /// \param Method The method that this instance message is invoking, if
- /// already known.
- ///
- /// \param LBracLoc The location of the opening square bracket ']'.
- ///
- /// \param RBracLoc The location of the closing square bracket ']'.
- ///
- /// \param ArgsIn The message arguments.
- ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
- QualType ReceiverType,
- SourceLocation SuperLoc,
- Selector Sel,
- ObjCMethodDecl *Method,
- SourceLocation LBracLoc,
- ArrayRef<SourceLocation> SelectorLocs,
- SourceLocation RBracLoc,
- MultiExprArg ArgsIn,
- bool isImplicit) {
- assert((Receiver || SuperLoc.isValid()) && "If the Receiver is null, the "
- "SuperLoc must be valid so we can "
- "use it instead.");
- // The location of the receiver.
- SourceLocation Loc = SuperLoc.isValid() ? SuperLoc : Receiver->getBeginLoc();
- SourceRange RecRange =
- SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange();
- ArrayRef<SourceLocation> SelectorSlotLocs;
- if (!SelectorLocs.empty() && SelectorLocs.front().isValid())
- SelectorSlotLocs = SelectorLocs;
- else
- SelectorSlotLocs = Loc;
- SourceLocation SelLoc = SelectorSlotLocs.front();
- if (LBracLoc.isInvalid()) {
- Diag(Loc, diag::err_missing_open_square_message_send)
- << FixItHint::CreateInsertion(Loc, "[");
- LBracLoc = Loc;
- }
- // If we have a receiver expression, perform appropriate promotions
- // and determine receiver type.
- if (Receiver) {
- if (Receiver->hasPlaceholderType()) {
- ExprResult Result;
- if (Receiver->getType() == Context.UnknownAnyTy)
- Result = forceUnknownAnyToType(Receiver, Context.getObjCIdType());
- else
- Result = CheckPlaceholderExpr(Receiver);
- if (Result.isInvalid()) return ExprError();
- Receiver = Result.get();
- }
- if (Receiver->isTypeDependent()) {
- // If the receiver is type-dependent, we can't type-check anything
- // at this point. Build a dependent expression.
- unsigned NumArgs = ArgsIn.size();
- Expr **Args = ArgsIn.data();
- assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return ObjCMessageExpr::Create(
- Context, Context.DependentTy, VK_PRValue, LBracLoc, Receiver, Sel,
- SelectorLocs, /*Method=*/nullptr, ArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
- }
- // If necessary, apply function/array conversion to the receiver.
- // C99 6.7.5.3p[7,8].
- ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver);
- if (Result.isInvalid())
- return ExprError();
- Receiver = Result.get();
- ReceiverType = Receiver->getType();
- // If the receiver is an ObjC pointer, a block pointer, or an
- // __attribute__((NSObject)) pointer, we don't need to do any
- // special conversion in order to look up a receiver.
- if (ReceiverType->isObjCRetainableType()) {
- // do nothing
- } else if (!getLangOpts().ObjCAutoRefCount &&
- !Context.getObjCIdType().isNull() &&
- (ReceiverType->isPointerType() ||
- ReceiverType->isIntegerType())) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- // But not in ARC.
- Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << RecRange;
- if (ReceiverType->isPointerType()) {
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_CPointerToObjCPointerCast).get();
- } else {
- // TODO: specialized warning on null receivers?
- bool IsNull = Receiver->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull);
- CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- Kind).get();
- }
- ReceiverType = Receiver->getType();
- } else if (getLangOpts().CPlusPlus) {
- // The receiver must be a complete type.
- if (RequireCompleteType(Loc, Receiver->getType(),
- diag::err_incomplete_receiver_type))
- return ExprError();
- ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
- if (result.isUsable()) {
- Receiver = result.get();
- ReceiverType = Receiver->getType();
- }
- }
- }
- // There's a somewhat weird interaction here where we assume that we
- // won't actually have a method unless we also don't need to do some
- // of the more detailed type-checking on the receiver.
- if (!Method) {
- // Handle messages to id and __kindof types (where we use the
- // global method pool).
- const ObjCObjectType *typeBound = nullptr;
- bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context,
- typeBound);
- if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
- (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
- SmallVector<ObjCMethodDecl*, 4> Methods;
- // If we have a type bound, further filter the methods.
- CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/,
- true/*CheckTheOther*/, typeBound);
- if (!Methods.empty()) {
- // We choose the first method as the initial candidate, then try to
- // select a better one.
- Method = Methods[0];
- if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods))
- Method = BestMethod;
- if (!AreMultipleMethodsInGlobalPool(Sel, Method,
- SourceRange(LBracLoc, RBracLoc),
- receiverIsIdLike, Methods))
- DiagnoseUseOfDecl(Method, SelectorSlotLocs);
- }
- } else if (ReceiverType->isObjCClassOrClassKindOfType() ||
- ReceiverType->isObjCQualifiedClassType()) {
- // Handle messages to Class.
- // We allow sending a message to a qualified Class ("Class<foo>"), which
- // is ok as long as one of the protocols implements the selector (if not,
- // warn).
- if (!ReceiverType->isObjCClassOrClassKindOfType()) {
- const ObjCObjectPointerType *QClassTy
- = ReceiverType->getAsObjCQualifiedClassType();
- // Search protocols for class methods.
- Method = LookupMethodInQualifiedType(Sel, QClassTy, false);
- if (!Method) {
- Method = LookupMethodInQualifiedType(Sel, QClassTy, true);
- // warn if instance method found for a Class message.
- if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) {
- Diag(SelLoc, diag::warn_instance_method_on_class_found)
- << Method->getSelector() << Sel;
- Diag(Method->getLocation(), diag::note_method_declared_at)
- << Method->getDeclName();
- }
- }
- } else {
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
- // As a guess, try looking for the method in the current interface.
- // This very well may not produce the "right" method.
- // First check the public methods in the class interface.
- Method = ClassDecl->lookupClassMethod(Sel);
- if (!Method)
- Method = ClassDecl->lookupPrivateClassMethod(Sel);
- if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs))
- return ExprError();
- }
- }
- if (!Method) {
- // If not messaging 'self', look for any factory method named 'Sel'.
- if (!Receiver || !isSelfExpr(Receiver)) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- SmallVector<ObjCMethodDecl*, 4> Methods;
- CollectMultipleMethodsInGlobalPool(Sel, Methods,
- false/*InstanceFirst*/,
- true/*CheckTheOther*/);
- if (!Methods.empty()) {
- // We choose the first method as the initial candidate, then try
- // to select a better one.
- Method = Methods[0];
- // If we find an instance method, emit warning.
- if (Method->isInstanceMethod()) {
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(SelLoc, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(LBracLoc, RBracLoc);
- }
- }
- if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
- Methods))
- Method = BestMethod;
- }
- }
- }
- }
- } else {
- ObjCInterfaceDecl *ClassDecl = nullptr;
- // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
- // long as one of the protocols implements the selector (if not, warn).
- // And as long as message is not deprecated/unavailable (warn if it is).
- if (const ObjCObjectPointerType *QIdTy
- = ReceiverType->getAsObjCQualifiedIdType()) {
- // Search protocols for instance methods.
- Method = LookupMethodInQualifiedType(Sel, QIdTy, true);
- if (!Method)
- Method = LookupMethodInQualifiedType(Sel, QIdTy, false);
- if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs))
- return ExprError();
- } else if (const ObjCObjectPointerType *OCIType
- = ReceiverType->getAsObjCInterfacePointerType()) {
- // We allow sending a message to a pointer to an interface (an object).
- ClassDecl = OCIType->getInterfaceDecl();
- // Try to complete the type. Under ARC, this is a hard error from which
- // we don't try to recover.
- // FIXME: In the non-ARC case, this will still be a hard error if the
- // definition is found in a module that's not visible.
- const ObjCInterfaceDecl *forwardClass = nullptr;
- if (RequireCompleteType(Loc, OCIType->getPointeeType(),
- getLangOpts().ObjCAutoRefCount
- ? diag::err_arc_receiver_forward_instance
- : diag::warn_receiver_forward_instance,
- RecRange)) {
- if (getLangOpts().ObjCAutoRefCount)
- return ExprError();
- forwardClass = OCIType->getInterfaceDecl();
- Diag(Receiver ? Receiver->getBeginLoc() : SuperLoc,
- diag::note_receiver_is_id);
- Method = nullptr;
- } else {
- Method = ClassDecl->lookupInstanceMethod(Sel);
- }
- if (!Method)
- // Search protocol qualifiers.
- Method = LookupMethodInQualifiedType(Sel, OCIType, true);
- if (!Method) {
- // If we have implementations in scope, check "private" methods.
- Method = ClassDecl->lookupPrivateMethod(Sel);
- if (!Method && getLangOpts().ObjCAutoRefCount) {
- Diag(SelLoc, diag::err_arc_may_not_respond)
- << OCIType->getPointeeType() << Sel << RecRange
- << SourceRange(SelectorLocs.front(), SelectorLocs.back());
- return ExprError();
- }
- if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
- // If we still haven't found a method, look in the global pool. This
- // behavior isn't very desirable, however we need it for GCC
- // compatibility. FIXME: should we deviate??
- if (OCIType->qual_empty()) {
- SmallVector<ObjCMethodDecl*, 4> Methods;
- CollectMultipleMethodsInGlobalPool(Sel, Methods,
- true/*InstanceFirst*/,
- false/*CheckTheOther*/);
- if (!Methods.empty()) {
- // We choose the first method as the initial candidate, then try
- // to select a better one.
- Method = Methods[0];
- if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
- Methods))
- Method = BestMethod;
- AreMultipleMethodsInGlobalPool(Sel, Method,
- SourceRange(LBracLoc, RBracLoc),
- true/*receiverIdOrClass*/,
- Methods);
- }
- if (Method && !forwardClass)
- Diag(SelLoc, diag::warn_maynot_respond)
- << OCIType->getInterfaceDecl()->getIdentifier()
- << Sel << RecRange;
- }
- }
- }
- if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, forwardClass))
- return ExprError();
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << RecRange;
- return ExprError();
- }
- }
- }
- FunctionScopeInfo *DIFunctionScopeInfo =
- (Method && Method->getMethodFamily() == OMF_init)
- ? getEnclosingFunction() : nullptr;
- if (Method && Method->isDirectMethod()) {
- if (ReceiverType->isObjCIdType() && !isImplicit) {
- Diag(Receiver->getExprLoc(),
- diag::err_messaging_unqualified_id_with_direct_method);
- Diag(Method->getLocation(), diag::note_direct_method_declared_at)
- << Method->getDeclName();
- }
- // Under ARC, self can't be assigned, and doing a direct call to `self`
- // when it's a Class is hence safe. For other cases, we can't trust `self`
- // is what we think it is, so we reject it.
- if (ReceiverType->isObjCClassType() && !isImplicit &&
- !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) {
- {
- auto Builder = Diag(Receiver->getExprLoc(),
- diag::err_messaging_class_with_direct_method);
- if (Receiver->isObjCSelfExpr()) {
- Builder.AddFixItHint(FixItHint::CreateReplacement(
- RecRange, Method->getClassInterface()->getName()));
- }
- }
- Diag(Method->getLocation(), diag::note_direct_method_declared_at)
- << Method->getDeclName();
- }
- if (SuperLoc.isValid()) {
- {
- auto Builder =
- Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
- if (ReceiverType->isObjCClassType()) {
- Builder.AddFixItHint(FixItHint::CreateReplacement(
- SuperLoc, Method->getClassInterface()->getName()));
- } else {
- Builder.AddFixItHint(FixItHint::CreateReplacement(SuperLoc, "self"));
- }
- }
- Diag(Method->getLocation(), diag::note_direct_method_declared_at)
- << Method->getDeclName();
- }
- } else if (ReceiverType->isObjCIdType() && !isImplicit) {
- Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
- }
- if (DIFunctionScopeInfo &&
- DIFunctionScopeInfo->ObjCIsDesignatedInit &&
- (SuperLoc.isValid() || isSelfExpr(Receiver))) {
- bool isDesignatedInitChain = false;
- if (SuperLoc.isValid()) {
- if (const ObjCObjectPointerType *
- OCIType = ReceiverType->getAsObjCInterfacePointerType()) {
- if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) {
- // Either we know this is a designated initializer or we
- // conservatively assume it because we don't know for sure.
- if (!ID->declaresOrInheritsDesignatedInitializers() ||
- ID->isDesignatedInitializer(Sel)) {
- isDesignatedInitChain = true;
- DIFunctionScopeInfo->ObjCWarnForNoDesignatedInitChain = false;
- }
- }
- }
- }
- if (!isDesignatedInitChain) {
- const ObjCMethodDecl *InitMethod = nullptr;
- bool isDesignated =
- getCurMethodDecl()->isDesignatedInitializerForTheInterface(&InitMethod);
- assert(isDesignated && InitMethod);
- (void)isDesignated;
- Diag(SelLoc, SuperLoc.isValid() ?
- diag::warn_objc_designated_init_non_designated_init_call :
- diag::warn_objc_designated_init_non_super_designated_init_call);
- Diag(InitMethod->getLocation(),
- diag::note_objc_designated_init_marked_here);
- }
- }
- if (DIFunctionScopeInfo &&
- DIFunctionScopeInfo->ObjCIsSecondaryInit &&
- (SuperLoc.isValid() || isSelfExpr(Receiver))) {
- if (SuperLoc.isValid()) {
- Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call);
- } else {
- DIFunctionScopeInfo->ObjCWarnForNoInitDelegation = false;
- }
- }
- // Check the message arguments.
- unsigned NumArgs = ArgsIn.size();
- Expr **Args = ArgsIn.data();
- QualType ReturnType;
- ExprValueKind VK = VK_PRValue;
- bool ClassMessage = (ReceiverType->isObjCClassType() ||
- ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(Receiver, ReceiverType,
- MultiExprArg(Args, NumArgs), Sel, SelectorLocs,
- Method, ClassMessage, SuperLoc.isValid(),
- LBracLoc, RBracLoc, RecRange, ReturnType, VK))
- return ExprError();
- if (Method && !Method->getReturnType()->isVoidType() &&
- RequireCompleteType(LBracLoc, Method->getReturnType(),
- diag::err_illegal_message_expr_incomplete_type))
- return ExprError();
- // In ARC, forbid the user from sending messages to
- // retain/release/autorelease/dealloc/retainCount explicitly.
- if (getLangOpts().ObjCAutoRefCount) {
- ObjCMethodFamily family =
- (Method ? Method->getMethodFamily() : Sel.getMethodFamily());
- switch (family) {
- case OMF_init:
- if (Method)
- checkInitMethod(Method, ReceiverType);
- break;
- case OMF_None:
- case OMF_alloc:
- case OMF_copy:
- case OMF_finalize:
- case OMF_mutableCopy:
- case OMF_new:
- case OMF_self:
- case OMF_initialize:
- break;
- case OMF_dealloc:
- case OMF_retain:
- case OMF_release:
- case OMF_autorelease:
- case OMF_retainCount:
- Diag(SelLoc, diag::err_arc_illegal_explicit_message)
- << Sel << RecRange;
- break;
- case OMF_performSelector:
- if (Method && NumArgs >= 1) {
- if (const auto *SelExp =
- dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens())) {
- Selector ArgSel = SelExp->getSelector();
- ObjCMethodDecl *SelMethod =
- LookupInstanceMethodInGlobalPool(ArgSel,
- SelExp->getSourceRange());
- if (!SelMethod)
- SelMethod =
- LookupFactoryMethodInGlobalPool(ArgSel,
- SelExp->getSourceRange());
- if (SelMethod) {
- ObjCMethodFamily SelFamily = SelMethod->getMethodFamily();
- switch (SelFamily) {
- case OMF_alloc:
- case OMF_copy:
- case OMF_mutableCopy:
- case OMF_new:
- case OMF_init:
- // Issue error, unless ns_returns_not_retained.
- if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
- // selector names a +1 method
- Diag(SelLoc,
- diag::err_arc_perform_selector_retains);
- Diag(SelMethod->getLocation(), diag::note_method_declared_at)
- << SelMethod->getDeclName();
- }
- break;
- default:
- // +0 call. OK. unless ns_returns_retained.
- if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
- // selector names a +1 method
- Diag(SelLoc,
- diag::err_arc_perform_selector_retains);
- Diag(SelMethod->getLocation(), diag::note_method_declared_at)
- << SelMethod->getDeclName();
- }
- break;
- }
- }
- } else {
- // error (may leak).
- Diag(SelLoc, diag::warn_arc_perform_selector_leaks);
- Diag(Args[0]->getExprLoc(), diag::note_used_here);
- }
- }
- break;
- }
- }
- DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
- // Construct the appropriate ObjCMessageExpr instance.
- ObjCMessageExpr *Result;
- if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(
- Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
- else {
- Result = ObjCMessageExpr::Create(
- Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLocs, Method,
- ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
- if (!isImplicit)
- checkCocoaAPI(*this, Result);
- }
- if (Method) {
- bool IsClassObjectCall = ClassMessage;
- // 'self' message receivers in class methods should be treated as message
- // sends to the class object in order for the semantic checks to be
- // performed correctly. Messages to 'super' already count as class messages,
- // so they don't need to be handled here.
- if (Receiver && isSelfExpr(Receiver)) {
- if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
- if (OPT->getObjectType()->isObjCClass()) {
- if (const auto *CurMeth = getCurMethodDecl()) {
- IsClassObjectCall = true;
- ReceiverType =
- Context.getObjCInterfaceType(CurMeth->getClassInterface());
- }
- }
- }
- }
- checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
- ReceiverType, IsClassObjectCall);
- }
- if (getLangOpts().ObjCAutoRefCount) {
- // In ARC, annotate delegate init calls.
- if (Result->getMethodFamily() == OMF_init &&
- (SuperLoc.isValid() || isSelfExpr(Receiver))) {
- // Only consider init calls *directly* in init implementations,
- // not within blocks.
- ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext);
- if (method && method->getMethodFamily() == OMF_init) {
- // The implicit assignment to self means we also don't want to
- // consume the result.
- Result->setDelegateInitCall(true);
- return Result;
- }
- }
- // In ARC, check for message sends which are likely to introduce
- // retain cycles.
- checkRetainCycles(Result);
- }
- if (getLangOpts().ObjCWeak) {
- if (!isImplicit && Method) {
- if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
- bool IsWeak =
- Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak;
- if (!IsWeak && Sel.isUnarySelector())
- IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
- if (IsWeak && !isUnevaluatedContext() &&
- !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, LBracLoc))
- getCurFunction()->recordUseOfWeak(Result, Prop);
- }
- }
- }
- CheckObjCCircularContainer(Result);
- return MaybeBindToTemporary(Result);
- }
- static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) {
- if (ObjCSelectorExpr *OSE =
- dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) {
- Selector Sel = OSE->getSelector();
- SourceLocation Loc = OSE->getAtLoc();
- auto Pos = S.ReferencedSelectors.find(Sel);
- if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc)
- S.ReferencedSelectors.erase(Pos);
- }
- }
- // ActOnInstanceMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from Sel.getNumArgs().
- ExprResult Sema::ActOnInstanceMessage(Scope *S,
- Expr *Receiver,
- Selector Sel,
- SourceLocation LBracLoc,
- ArrayRef<SourceLocation> SelectorLocs,
- SourceLocation RBracLoc,
- MultiExprArg Args) {
- if (!Receiver)
- return ExprError();
- // A ParenListExpr can show up while doing error recovery with invalid code.
- if (isa<ParenListExpr>(Receiver)) {
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver);
- if (Result.isInvalid()) return ExprError();
- Receiver = Result.get();
- }
- if (RespondsToSelectorSel.isNull()) {
- IdentifierInfo *SelectorId = &Context.Idents.get("respondsToSelector");
- RespondsToSelectorSel = Context.Selectors.getUnarySelector(SelectorId);
- }
- if (Sel == RespondsToSelectorSel)
- RemoveSelectorFromWarningCache(*this, Args[0]);
- return BuildInstanceMessage(Receiver, Receiver->getType(),
- /*SuperLoc=*/SourceLocation(), Sel,
- /*Method=*/nullptr, LBracLoc, SelectorLocs,
- RBracLoc, Args);
- }
- enum ARCConversionTypeClass {
- /// int, void, struct A
- ACTC_none,
- /// id, void (^)()
- ACTC_retainable,
- /// id*, id***, void (^*)(),
- ACTC_indirectRetainable,
- /// void* might be a normal C type, or it might a CF type.
- ACTC_voidPtr,
- /// struct A*
- ACTC_coreFoundation
- };
- static bool isAnyRetainable(ARCConversionTypeClass ACTC) {
- return (ACTC == ACTC_retainable ||
- ACTC == ACTC_coreFoundation ||
- ACTC == ACTC_voidPtr);
- }
- static bool isAnyCLike(ARCConversionTypeClass ACTC) {
- return ACTC == ACTC_none ||
- ACTC == ACTC_voidPtr ||
- ACTC == ACTC_coreFoundation;
- }
- static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
- bool isIndirect = false;
- // Ignore an outermost reference type.
- if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
- type = ref->getPointeeType();
- isIndirect = true;
- }
- // Drill through pointers and arrays recursively.
- while (true) {
- if (const PointerType *ptr = type->getAs<PointerType>()) {
- type = ptr->getPointeeType();
- // The first level of pointer may be the innermost pointer on a CF type.
- if (!isIndirect) {
- if (type->isVoidType()) return ACTC_voidPtr;
- if (type->isRecordType()) return ACTC_coreFoundation;
- }
- } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
- type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
- } else {
- break;
- }
- isIndirect = true;
- }
- if (isIndirect) {
- if (type->isObjCARCBridgableType())
- return ACTC_indirectRetainable;
- return ACTC_none;
- }
- if (type->isObjCARCBridgableType())
- return ACTC_retainable;
- return ACTC_none;
- }
- namespace {
- /// A result from the cast checker.
- enum ACCResult {
- /// Cannot be casted.
- ACC_invalid,
- /// Can be safely retained or not retained.
- ACC_bottom,
- /// Can be casted at +0.
- ACC_plusZero,
- /// Can be casted at +1.
- ACC_plusOne
- };
- ACCResult merge(ACCResult left, ACCResult right) {
- if (left == right) return left;
- if (left == ACC_bottom) return right;
- if (right == ACC_bottom) return left;
- return ACC_invalid;
- }
- /// A checker which white-lists certain expressions whose conversion
- /// to or from retainable type would otherwise be forbidden in ARC.
- class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> {
- typedef StmtVisitor<ARCCastChecker, ACCResult> super;
- ASTContext &Context;
- ARCConversionTypeClass SourceClass;
- ARCConversionTypeClass TargetClass;
- bool Diagnose;
- static bool isCFType(QualType type) {
- // Someday this can use ns_bridged. For now, it has to do this.
- return type->isCARCBridgableType();
- }
- public:
- ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source,
- ARCConversionTypeClass target, bool diagnose)
- : Context(Context), SourceClass(source), TargetClass(target),
- Diagnose(diagnose) {}
- using super::Visit;
- ACCResult Visit(Expr *e) {
- return super::Visit(e->IgnoreParens());
- }
- ACCResult VisitStmt(Stmt *s) {
- return ACC_invalid;
- }
- /// Null pointer constants can be casted however you please.
- ACCResult VisitExpr(Expr *e) {
- if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- return ACC_bottom;
- return ACC_invalid;
- }
- /// Objective-C string literals can be safely casted.
- ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) {
- // If we're casting to any retainable type, go ahead. Global
- // strings are immune to retains, so this is bottom.
- if (isAnyRetainable(TargetClass)) return ACC_bottom;
- return ACC_invalid;
- }
- /// Look through certain implicit and explicit casts.
- ACCResult VisitCastExpr(CastExpr *e) {
- switch (e->getCastKind()) {
- case CK_NullToPointer:
- return ACC_bottom;
- case CK_NoOp:
- case CK_LValueToRValue:
- case CK_BitCast:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- return Visit(e->getSubExpr());
- default:
- return ACC_invalid;
- }
- }
- /// Look through unary extension.
- ACCResult VisitUnaryExtension(UnaryOperator *e) {
- return Visit(e->getSubExpr());
- }
- /// Ignore the LHS of a comma operator.
- ACCResult VisitBinComma(BinaryOperator *e) {
- return Visit(e->getRHS());
- }
- /// Conditional operators are okay if both sides are okay.
- ACCResult VisitConditionalOperator(ConditionalOperator *e) {
- ACCResult left = Visit(e->getTrueExpr());
- if (left == ACC_invalid) return ACC_invalid;
- return merge(left, Visit(e->getFalseExpr()));
- }
- /// Look through pseudo-objects.
- ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) {
- // If we're getting here, we should always have a result.
- return Visit(e->getResultExpr());
- }
- /// Statement expressions are okay if their result expression is okay.
- ACCResult VisitStmtExpr(StmtExpr *e) {
- return Visit(e->getSubStmt()->body_back());
- }
- /// Some declaration references are okay.
- ACCResult VisitDeclRefExpr(DeclRefExpr *e) {
- VarDecl *var = dyn_cast<VarDecl>(e->getDecl());
- // References to global constants are okay.
- if (isAnyRetainable(TargetClass) &&
- isAnyRetainable(SourceClass) &&
- var &&
- !var->hasDefinition(Context) &&
- var->getType().isConstQualified()) {
- // In system headers, they can also be assumed to be immune to retains.
- // These are things like 'kCFStringTransformToLatin'.
- if (Context.getSourceManager().isInSystemHeader(var->getLocation()))
- return ACC_bottom;
- return ACC_plusZero;
- }
- // Nothing else.
- return ACC_invalid;
- }
- /// Some calls are okay.
- ACCResult VisitCallExpr(CallExpr *e) {
- if (FunctionDecl *fn = e->getDirectCallee())
- if (ACCResult result = checkCallToFunction(fn))
- return result;
- return super::VisitCallExpr(e);
- }
- ACCResult checkCallToFunction(FunctionDecl *fn) {
- // Require a CF*Ref return type.
- if (!isCFType(fn->getReturnType()))
- return ACC_invalid;
- if (!isAnyRetainable(TargetClass))
- return ACC_invalid;
- // Honor an explicit 'not retained' attribute.
- if (fn->hasAttr<CFReturnsNotRetainedAttr>())
- return ACC_plusZero;
- // Honor an explicit 'retained' attribute, except that for
- // now we're not going to permit implicit handling of +1 results,
- // because it's a bit frightening.
- if (fn->hasAttr<CFReturnsRetainedAttr>())
- return Diagnose ? ACC_plusOne
- : ACC_invalid; // ACC_plusOne if we start accepting this
- // Recognize this specific builtin function, which is used by CFSTR.
- unsigned builtinID = fn->getBuiltinID();
- if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString)
- return ACC_bottom;
- // Otherwise, don't do anything implicit with an unaudited function.
- if (!fn->hasAttr<CFAuditedTransferAttr>())
- return ACC_invalid;
- // Otherwise, it's +0 unless it follows the create convention.
- if (ento::coreFoundation::followsCreateRule(fn))
- return Diagnose ? ACC_plusOne
- : ACC_invalid; // ACC_plusOne if we start accepting this
- return ACC_plusZero;
- }
- ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) {
- return checkCallToMethod(e->getMethodDecl());
- }
- ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) {
- ObjCMethodDecl *method;
- if (e->isExplicitProperty())
- method = e->getExplicitProperty()->getGetterMethodDecl();
- else
- method = e->getImplicitPropertyGetter();
- return checkCallToMethod(method);
- }
- ACCResult checkCallToMethod(ObjCMethodDecl *method) {
- if (!method) return ACC_invalid;
- // Check for message sends to functions returning CF types. We
- // just obey the Cocoa conventions with these, even though the
- // return type is CF.
- if (!isAnyRetainable(TargetClass) || !isCFType(method->getReturnType()))
- return ACC_invalid;
- // If the method is explicitly marked not-retained, it's +0.
- if (method->hasAttr<CFReturnsNotRetainedAttr>())
- return ACC_plusZero;
- // If the method is explicitly marked as returning retained, or its
- // selector follows a +1 Cocoa convention, treat it as +1.
- if (method->hasAttr<CFReturnsRetainedAttr>())
- return ACC_plusOne;
- switch (method->getSelector().getMethodFamily()) {
- case OMF_alloc:
- case OMF_copy:
- case OMF_mutableCopy:
- case OMF_new:
- return ACC_plusOne;
- default:
- // Otherwise, treat it as +0.
- return ACC_plusZero;
- }
- }
- };
- } // end anonymous namespace
- bool Sema::isKnownName(StringRef name) {
- if (name.empty())
- return false;
- LookupResult R(*this, &Context.Idents.get(name), SourceLocation(),
- Sema::LookupOrdinaryName);
- return LookupName(R, TUScope, false);
- }
- template <typename DiagBuilderT>
- static void addFixitForObjCARCConversion(
- Sema &S, DiagBuilderT &DiagB, Sema::CheckedConversionKind CCK,
- SourceLocation afterLParen, QualType castType, Expr *castExpr,
- Expr *realCast, const char *bridgeKeyword, const char *CFBridgeName) {
- // We handle C-style and implicit casts here.
- switch (CCK) {
- case Sema::CCK_ImplicitConversion:
- case Sema::CCK_ForBuiltinOverloadedOp:
- case Sema::CCK_CStyleCast:
- case Sema::CCK_OtherCast:
- break;
- case Sema::CCK_FunctionalCast:
- return;
- }
- if (CFBridgeName) {
- if (CCK == Sema::CCK_OtherCast) {
- if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
- SourceRange range(NCE->getOperatorLoc(),
- NCE->getAngleBrackets().getEnd());
- SmallString<32> BridgeCall;
- SourceManager &SM = S.getSourceManager();
- char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
- if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts()))
- BridgeCall += ' ';
- BridgeCall += CFBridgeName;
- DiagB.AddFixItHint(FixItHint::CreateReplacement(range, BridgeCall));
- }
- return;
- }
- Expr *castedE = castExpr;
- if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE))
- castedE = CCE->getSubExpr();
- castedE = castedE->IgnoreImpCasts();
- SourceRange range = castedE->getSourceRange();
- SmallString<32> BridgeCall;
- SourceManager &SM = S.getSourceManager();
- char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
- if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts()))
- BridgeCall += ' ';
- BridgeCall += CFBridgeName;
- if (isa<ParenExpr>(castedE)) {
- DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- BridgeCall));
- } else {
- BridgeCall += '(';
- DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- BridgeCall));
- DiagB.AddFixItHint(FixItHint::CreateInsertion(
- S.getLocForEndOfToken(range.getEnd()),
- ")"));
- }
- return;
- }
- if (CCK == Sema::CCK_CStyleCast) {
- DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
- } else if (CCK == Sema::CCK_OtherCast) {
- if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
- std::string castCode = "(";
- castCode += bridgeKeyword;
- castCode += castType.getAsString();
- castCode += ")";
- SourceRange Range(NCE->getOperatorLoc(),
- NCE->getAngleBrackets().getEnd());
- DiagB.AddFixItHint(FixItHint::CreateReplacement(Range, castCode));
- }
- } else {
- std::string castCode = "(";
- castCode += bridgeKeyword;
- castCode += castType.getAsString();
- castCode += ")";
- Expr *castedE = castExpr->IgnoreImpCasts();
- SourceRange range = castedE->getSourceRange();
- if (isa<ParenExpr>(castedE)) {
- DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- castCode));
- } else {
- castCode += "(";
- DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- castCode));
- DiagB.AddFixItHint(FixItHint::CreateInsertion(
- S.getLocForEndOfToken(range.getEnd()),
- ")"));
- }
- }
- }
- template <typename T>
- static inline T *getObjCBridgeAttr(const TypedefType *TD) {
- TypedefNameDecl *TDNDecl = TD->getDecl();
- QualType QT = TDNDecl->getUnderlyingType();
- if (QT->isPointerType()) {
- QT = QT->getPointeeType();
- if (const RecordType *RT = QT->getAs<RecordType>()) {
- for (auto *Redecl : RT->getDecl()->getMostRecentDecl()->redecls()) {
- if (auto *attr = Redecl->getAttr<T>())
- return attr;
- }
- }
- }
- return nullptr;
- }
- static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
- TypedefNameDecl *&TDNDecl) {
- while (const auto *TD = T->getAs<TypedefType>()) {
- TDNDecl = TD->getDecl();
- if (ObjCBridgeRelatedAttr *ObjCBAttr =
- getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD))
- return ObjCBAttr;
- T = TDNDecl->getUnderlyingType();
- }
- return nullptr;
- }
- static void
- diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
- QualType castType, ARCConversionTypeClass castACTC,
- Expr *castExpr, Expr *realCast,
- ARCConversionTypeClass exprACTC,
- Sema::CheckedConversionKind CCK) {
- SourceLocation loc =
- (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
- if (S.makeUnavailableInSystemHeader(loc,
- UnavailableAttr::IR_ARCForbiddenConversion))
- return;
- QualType castExprType = castExpr->getType();
- // Defer emitting a diagnostic for bridge-related casts; that will be
- // handled by CheckObjCBridgeRelatedConversions.
- TypedefNameDecl *TDNDecl = nullptr;
- if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
- ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) ||
- (exprACTC == ACTC_coreFoundation && castACTC == ACTC_retainable &&
- ObjCBridgeRelatedAttrFromType(castExprType, TDNDecl)))
- return;
- unsigned srcKind = 0;
- switch (exprACTC) {
- case ACTC_none:
- case ACTC_coreFoundation:
- case ACTC_voidPtr:
- srcKind = (castExprType->isPointerType() ? 1 : 0);
- break;
- case ACTC_retainable:
- srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
- break;
- case ACTC_indirectRetainable:
- srcKind = 4;
- break;
- }
- // Check whether this could be fixed with a bridge cast.
- SourceLocation afterLParen = S.getLocForEndOfToken(castRange.getBegin());
- SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc;
- unsigned convKindForDiag = Sema::isCast(CCK) ? 0 : 1;
- // Bridge from an ARC type to a CF type.
- if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) {
- S.Diag(loc, diag::err_arc_cast_requires_bridge)
- << convKindForDiag
- << 2 // of C pointer type
- << castExprType
- << unsigned(castType->isBlockPointerType()) // to ObjC|block type
- << castType
- << castRange
- << castExpr->getSourceRange();
- bool br = S.isKnownName("CFBridgingRelease");
- ACCResult CreateRule =
- ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
- assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
- if (CreateRule != ACC_plusOne)
- {
- auto DiagB = (CCK != Sema::CCK_OtherCast)
- ? S.Diag(noteLoc, diag::note_arc_bridge)
- : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
- addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge ",
- nullptr);
- }
- if (CreateRule != ACC_plusZero)
- {
- auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
- ? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer)
- << castExprType
- : S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_transfer)
- << castExprType << br;
- addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge_transfer ",
- br ? "CFBridgingRelease" : nullptr);
- }
- return;
- }
- // Bridge from a CF type to an ARC type.
- if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
- bool br = S.isKnownName("CFBridgingRetain");
- S.Diag(loc, diag::err_arc_cast_requires_bridge)
- << convKindForDiag
- << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type
- << castExprType
- << 2 // to C pointer type
- << castType
- << castRange
- << castExpr->getSourceRange();
- ACCResult CreateRule =
- ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
- assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
- if (CreateRule != ACC_plusOne)
- {
- auto DiagB = (CCK != Sema::CCK_OtherCast)
- ? S.Diag(noteLoc, diag::note_arc_bridge)
- : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
- addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge ",
- nullptr);
- }
- if (CreateRule != ACC_plusZero)
- {
- auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
- ? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained)
- << castType
- : S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_retained)
- << castType << br;
- addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge_retained ",
- br ? "CFBridgingRetain" : nullptr);
- }
- return;
- }
- S.Diag(loc, diag::err_arc_mismatched_cast)
- << !convKindForDiag
- << srcKind << castExprType << castType
- << castRange << castExpr->getSourceRange();
- }
- template <typename TB>
- static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
- bool &HadTheAttribute, bool warn) {
- QualType T = castExpr->getType();
- HadTheAttribute = false;
- while (const auto *TD = T->getAs<TypedefType>()) {
- TypedefNameDecl *TDNDecl = TD->getDecl();
- if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
- if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
- HadTheAttribute = true;
- if (Parm->isStr("id"))
- return true;
- // Check for an existing type with this name.
- LookupResult R(S, DeclarationName(Parm), SourceLocation(),
- Sema::LookupOrdinaryName);
- if (S.LookupName(R, S.TUScope)) {
- NamedDecl *Target = R.getFoundDecl();
- if (Target && isa<ObjCInterfaceDecl>(Target)) {
- ObjCInterfaceDecl *ExprClass = cast<ObjCInterfaceDecl>(Target);
- if (const ObjCObjectPointerType *InterfacePointerType =
- castType->getAsObjCInterfacePointerType()) {
- ObjCInterfaceDecl *CastClass
- = InterfacePointerType->getObjectType()->getInterface();
- if ((CastClass == ExprClass) ||
- (CastClass && CastClass->isSuperClassOf(ExprClass)))
- return true;
- if (warn)
- S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge)
- << T << Target->getName() << castType->getPointeeType();
- return false;
- } else if (castType->isObjCIdType() ||
- (S.Context.ObjCObjectAdoptsQTypeProtocols(
- castType, ExprClass)))
- // ok to cast to 'id'.
- // casting to id<p-list> is ok if bridge type adopts all of
- // p-list protocols.
- return true;
- else {
- if (warn) {
- S.Diag(castExpr->getBeginLoc(), diag::warn_objc_invalid_bridge)
- << T << Target->getName() << castType;
- S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- S.Diag(Target->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- }
- } else if (!castType->isObjCIdType()) {
- S.Diag(castExpr->getBeginLoc(),
- diag::err_objc_cf_bridged_not_interface)
- << castExpr->getType() << Parm;
- S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- }
- return true;
- }
- return false;
- }
- T = TDNDecl->getUnderlyingType();
- }
- return true;
- }
- template <typename TB>
- static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr,
- bool &HadTheAttribute, bool warn) {
- QualType T = castType;
- HadTheAttribute = false;
- while (const auto *TD = T->getAs<TypedefType>()) {
- TypedefNameDecl *TDNDecl = TD->getDecl();
- if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
- if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
- HadTheAttribute = true;
- if (Parm->isStr("id"))
- return true;
- NamedDecl *Target = nullptr;
- // Check for an existing type with this name.
- LookupResult R(S, DeclarationName(Parm), SourceLocation(),
- Sema::LookupOrdinaryName);
- if (S.LookupName(R, S.TUScope)) {
- Target = R.getFoundDecl();
- if (Target && isa<ObjCInterfaceDecl>(Target)) {
- ObjCInterfaceDecl *CastClass = cast<ObjCInterfaceDecl>(Target);
- if (const ObjCObjectPointerType *InterfacePointerType =
- castExpr->getType()->getAsObjCInterfacePointerType()) {
- ObjCInterfaceDecl *ExprClass
- = InterfacePointerType->getObjectType()->getInterface();
- if ((CastClass == ExprClass) ||
- (ExprClass && CastClass->isSuperClassOf(ExprClass)))
- return true;
- if (warn) {
- S.Diag(castExpr->getBeginLoc(),
- diag::warn_objc_invalid_bridge_to_cf)
- << castExpr->getType()->getPointeeType() << T;
- S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- } else if (castExpr->getType()->isObjCIdType() ||
- (S.Context.QIdProtocolsAdoptObjCObjectProtocols(
- castExpr->getType(), CastClass)))
- // ok to cast an 'id' expression to a CFtype.
- // ok to cast an 'id<plist>' expression to CFtype provided plist
- // adopts all of CFtype's ObjetiveC's class plist.
- return true;
- else {
- if (warn) {
- S.Diag(castExpr->getBeginLoc(),
- diag::warn_objc_invalid_bridge_to_cf)
- << castExpr->getType() << castType;
- S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- S.Diag(Target->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- }
- }
- S.Diag(castExpr->getBeginLoc(),
- diag::err_objc_ns_bridged_invalid_cfobject)
- << castExpr->getType() << castType;
- S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- if (Target)
- S.Diag(Target->getBeginLoc(), diag::note_declared_at);
- return true;
- }
- return false;
- }
- T = TDNDecl->getUnderlyingType();
- }
- return true;
- }
- void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
- if (!getLangOpts().ObjC)
- return;
- // warn in presence of __bridge casting to or from a toll free bridge cast.
- ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
- ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
- if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
- bool HasObjCBridgeAttr;
- bool ObjCBridgeAttrWillNotWarn =
- CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
- false);
- if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
- return;
- bool HasObjCBridgeMutableAttr;
- bool ObjCBridgeMutableAttrWillNotWarn =
- CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
- HasObjCBridgeMutableAttr, false);
- if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
- return;
- if (HasObjCBridgeAttr)
- CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
- true);
- else if (HasObjCBridgeMutableAttr)
- CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
- HasObjCBridgeMutableAttr, true);
- }
- else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
- bool HasObjCBridgeAttr;
- bool ObjCBridgeAttrWillNotWarn =
- CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
- false);
- if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
- return;
- bool HasObjCBridgeMutableAttr;
- bool ObjCBridgeMutableAttrWillNotWarn =
- CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
- HasObjCBridgeMutableAttr, false);
- if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
- return;
- if (HasObjCBridgeAttr)
- CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
- true);
- else if (HasObjCBridgeMutableAttr)
- CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
- HasObjCBridgeMutableAttr, true);
- }
- }
- void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) {
- QualType SrcType = castExpr->getType();
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(castExpr)) {
- if (PRE->isExplicitProperty()) {
- if (ObjCPropertyDecl *PDecl = PRE->getExplicitProperty())
- SrcType = PDecl->getType();
- }
- else if (PRE->isImplicitProperty()) {
- if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter())
- SrcType = Getter->getReturnType();
- }
- }
- ARCConversionTypeClass srcExprACTC = classifyTypeForARCConversion(SrcType);
- ARCConversionTypeClass castExprACTC = classifyTypeForARCConversion(castType);
- if (srcExprACTC != ACTC_retainable || castExprACTC != ACTC_coreFoundation)
- return;
- CheckObjCBridgeRelatedConversions(castExpr->getBeginLoc(), castType, SrcType,
- castExpr);
- }
- bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr,
- CastKind &Kind) {
- if (!getLangOpts().ObjC)
- return false;
- ARCConversionTypeClass exprACTC =
- classifyTypeForARCConversion(castExpr->getType());
- ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
- if ((castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) ||
- (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)) {
- CheckTollFreeBridgeCast(castType, castExpr);
- Kind = (castACTC == ACTC_coreFoundation) ? CK_BitCast
- : CK_CPointerToObjCPointerCast;
- return true;
- }
- return false;
- }
- bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
- QualType DestType, QualType SrcType,
- ObjCInterfaceDecl *&RelatedClass,
- ObjCMethodDecl *&ClassMethod,
- ObjCMethodDecl *&InstanceMethod,
- TypedefNameDecl *&TDNDecl,
- bool CfToNs, bool Diagnose) {
- QualType T = CfToNs ? SrcType : DestType;
- ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl);
- if (!ObjCBAttr)
- return false;
- IdentifierInfo *RCId = ObjCBAttr->getRelatedClass();
- IdentifierInfo *CMId = ObjCBAttr->getClassMethod();
- IdentifierInfo *IMId = ObjCBAttr->getInstanceMethod();
- if (!RCId)
- return false;
- NamedDecl *Target = nullptr;
- // Check for an existing type with this name.
- LookupResult R(*this, DeclarationName(RCId), SourceLocation(),
- Sema::LookupOrdinaryName);
- if (!LookupName(R, TUScope)) {
- if (Diagnose) {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- Target = R.getFoundDecl();
- if (Target && isa<ObjCInterfaceDecl>(Target))
- RelatedClass = cast<ObjCInterfaceDecl>(Target);
- else {
- if (Diagnose) {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- if (Target)
- Diag(Target->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- // Check for an existing class method with the given selector name.
- if (CfToNs && CMId) {
- Selector Sel = Context.Selectors.getUnarySelector(CMId);
- ClassMethod = RelatedClass->lookupMethod(Sel, false);
- if (!ClassMethod) {
- if (Diagnose) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << false;
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- }
- // Check for an existing instance method with the given selector name.
- if (!CfToNs && IMId) {
- Selector Sel = Context.Selectors.getNullarySelector(IMId);
- InstanceMethod = RelatedClass->lookupMethod(Sel, true);
- if (!InstanceMethod) {
- if (Diagnose) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << true;
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- }
- return false;
- }
- }
- return true;
- }
- bool
- Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
- QualType DestType, QualType SrcType,
- Expr *&SrcExpr, bool Diagnose) {
- ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType);
- ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType);
- bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable);
- bool NsToCf = (rhsExprACTC == ACTC_retainable && lhsExprACTC == ACTC_coreFoundation);
- if (!CfToNs && !NsToCf)
- return false;
- ObjCInterfaceDecl *RelatedClass;
- ObjCMethodDecl *ClassMethod = nullptr;
- ObjCMethodDecl *InstanceMethod = nullptr;
- TypedefNameDecl *TDNDecl = nullptr;
- if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass,
- ClassMethod, InstanceMethod, TDNDecl,
- CfToNs, Diagnose))
- return false;
- if (CfToNs) {
- // Implicit conversion from CF to ObjC object is needed.
- if (ClassMethod) {
- if (Diagnose) {
- std::string ExpressionString = "[";
- ExpressionString += RelatedClass->getNameAsString();
- ExpressionString += " ";
- ExpressionString += ClassMethod->getSelector().getAsString();
- SourceLocation SrcExprEndLoc =
- getLocForEndOfToken(SrcExpr->getEndLoc());
- // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << ClassMethod->getSelector() << false
- << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(),
- ExpressionString)
- << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
- Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
- // Argument.
- Expr *args[] = { SrcExpr };
- ExprResult msg = BuildClassMessageImplicit(receiverType, false,
- ClassMethod->getLocation(),
- ClassMethod->getSelector(), ClassMethod,
- MultiExprArg(args, 1));
- SrcExpr = msg.get();
- }
- return true;
- }
- }
- else {
- // Implicit conversion from ObjC type to CF object is needed.
- if (InstanceMethod) {
- if (Diagnose) {
- std::string ExpressionString;
- SourceLocation SrcExprEndLoc =
- getLocForEndOfToken(SrcExpr->getEndLoc());
- if (InstanceMethod->isPropertyAccessor())
- if (const ObjCPropertyDecl *PDecl =
- InstanceMethod->findPropertyDecl()) {
- // fixit: ObjectExpr.propertyname when it is aproperty accessor.
- ExpressionString = ".";
- ExpressionString += PDecl->getNameAsString();
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
- }
- if (ExpressionString.empty()) {
- // Provide a fixit: [ObjectExpr InstanceMethod]
- ExpressionString = " ";
- ExpressionString += InstanceMethod->getSelector().getAsString();
- ExpressionString += "]";
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), "[")
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
- }
- Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
- Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- ExprResult msg = BuildInstanceMessageImplicit(
- SrcExpr, SrcType, InstanceMethod->getLocation(),
- InstanceMethod->getSelector(), InstanceMethod, std::nullopt);
- SrcExpr = msg.get();
- }
- return true;
- }
- }
- return false;
- }
- Sema::ARCConversionResult
- Sema::CheckObjCConversion(SourceRange castRange, QualType castType,
- Expr *&castExpr, CheckedConversionKind CCK,
- bool Diagnose, bool DiagnoseCFAudited,
- BinaryOperatorKind Opc) {
- QualType castExprType = castExpr->getType();
- // For the purposes of the classification, we assume reference types
- // will bind to temporaries.
- QualType effCastType = castType;
- if (const ReferenceType *ref = castType->getAs<ReferenceType>())
- effCastType = ref->getPointeeType();
- ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
- ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType);
- if (exprACTC == castACTC) {
- // Check for viability and report error if casting an rvalue to a
- // life-time qualifier.
- if (castACTC == ACTC_retainable &&
- (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
- castType != castExprType) {
- const Type *DT = castType.getTypePtr();
- QualType QDT = castType;
- // We desugar some types but not others. We ignore those
- // that cannot happen in a cast; i.e. auto, and those which
- // should not be de-sugared; i.e typedef.
- if (const ParenType *PT = dyn_cast<ParenType>(DT))
- QDT = PT->desugar();
- else if (const TypeOfType *TP = dyn_cast<TypeOfType>(DT))
- QDT = TP->desugar();
- else if (const AttributedType *AT = dyn_cast<AttributedType>(DT))
- QDT = AT->desugar();
- if (QDT != castType &&
- QDT.getObjCLifetime() != Qualifiers::OCL_None) {
- if (Diagnose) {
- SourceLocation loc = (castRange.isValid() ? castRange.getBegin()
- : castExpr->getExprLoc());
- Diag(loc, diag::err_arc_nolifetime_behavior);
- }
- return ACR_error;
- }
- }
- return ACR_okay;
- }
- // The life-time qualifier cast check above is all we need for ObjCWeak.
- // ObjCAutoRefCount has more restrictions on what is legal.
- if (!getLangOpts().ObjCAutoRefCount)
- return ACR_okay;
- if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay;
- // Allow all of these types to be cast to integer types (but not
- // vice-versa).
- if (castACTC == ACTC_none && castType->isIntegralType(Context))
- return ACR_okay;
- // Allow casts between pointers to lifetime types (e.g., __strong id*)
- // and pointers to void (e.g., cv void *). Casting from void* to lifetime*
- // must be explicit.
- // Allow conversions between pointers to lifetime types and coreFoundation
- // pointers too, but only when the conversions are explicit.
- if (exprACTC == ACTC_indirectRetainable &&
- (castACTC == ACTC_voidPtr ||
- (castACTC == ACTC_coreFoundation && isCast(CCK))))
- return ACR_okay;
- if (castACTC == ACTC_indirectRetainable &&
- (exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) &&
- isCast(CCK))
- return ACR_okay;
- switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {
- // For invalid casts, fall through.
- case ACC_invalid:
- break;
- // Do nothing for both bottom and +0.
- case ACC_bottom:
- case ACC_plusZero:
- return ACR_okay;
- // If the result is +1, consume it here.
- case ACC_plusOne:
- castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(),
- CK_ARCConsumeObject, castExpr, nullptr,
- VK_PRValue, FPOptionsOverride());
- Cleanup.setExprNeedsCleanups(true);
- return ACR_okay;
- }
- // If this is a non-implicit cast from id or block type to a
- // CoreFoundation type, delay complaining in case the cast is used
- // in an acceptable context.
- if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && isCast(CCK))
- return ACR_unbridged;
- // Issue a diagnostic about a missing @-sign when implicit casting a cstring
- // to 'NSString *', instead of falling through to report a "bridge cast"
- // diagnostic.
- if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
- CheckConversionToObjCLiteral(castType, castExpr, Diagnose))
- return ACR_error;
- // Do not issue "bridge cast" diagnostic when implicit casting
- // a retainable object to a CF type parameter belonging to an audited
- // CF API function. Let caller issue a normal type mismatched diagnostic
- // instead.
- if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
- castACTC != ACTC_coreFoundation) &&
- !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
- (Opc == BO_NE || Opc == BO_EQ))) {
- if (Diagnose)
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr,
- castExpr, exprACTC, CCK);
- return ACR_error;
- }
- return ACR_okay;
- }
- /// Given that we saw an expression with the ARCUnbridgedCastTy
- /// placeholder type, complain bitterly.
- void Sema::diagnoseARCUnbridgedCast(Expr *e) {
- // We expect the spurious ImplicitCastExpr to already have been stripped.
- assert(!e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
- CastExpr *realCast = cast<CastExpr>(e->IgnoreParens());
- SourceRange castRange;
- QualType castType;
- CheckedConversionKind CCK;
- if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) {
- castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc());
- castType = cast->getTypeAsWritten();
- CCK = CCK_CStyleCast;
- } else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) {
- castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange();
- castType = cast->getTypeAsWritten();
- CCK = CCK_OtherCast;
- } else {
- llvm_unreachable("Unexpected ImplicitCastExpr");
- }
- ARCConversionTypeClass castACTC =
- classifyTypeForARCConversion(castType.getNonReferenceType());
- Expr *castExpr = realCast->getSubExpr();
- assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable);
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, realCast, ACTC_retainable, CCK);
- }
- /// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast
- /// type, remove the placeholder cast.
- Expr *Sema::stripARCUnbridgedCast(Expr *e) {
- assert(e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
- if (ParenExpr *pe = dyn_cast<ParenExpr>(e)) {
- Expr *sub = stripARCUnbridgedCast(pe->getSubExpr());
- return new (Context) ParenExpr(pe->getLParen(), pe->getRParen(), sub);
- } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
- assert(uo->getOpcode() == UO_Extension);
- Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
- return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
- sub->getValueKind(), sub->getObjectKind(),
- uo->getOperatorLoc(), false,
- CurFPFeatureOverrides());
- } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
- assert(!gse->isResultDependent());
- unsigned n = gse->getNumAssocs();
- SmallVector<Expr *, 4> subExprs;
- SmallVector<TypeSourceInfo *, 4> subTypes;
- subExprs.reserve(n);
- subTypes.reserve(n);
- for (const GenericSelectionExpr::Association assoc : gse->associations()) {
- subTypes.push_back(assoc.getTypeSourceInfo());
- Expr *sub = assoc.getAssociationExpr();
- if (assoc.isSelected())
- sub = stripARCUnbridgedCast(sub);
- subExprs.push_back(sub);
- }
- return GenericSelectionExpr::Create(
- Context, gse->getGenericLoc(), gse->getControllingExpr(), subTypes,
- subExprs, gse->getDefaultLoc(), gse->getRParenLoc(),
- gse->containsUnexpandedParameterPack(), gse->getResultIndex());
- } else {
- assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!");
- return cast<ImplicitCastExpr>(e)->getSubExpr();
- }
- }
- bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
- QualType exprType) {
- QualType canCastType =
- Context.getCanonicalType(castType).getUnqualifiedType();
- QualType canExprType =
- Context.getCanonicalType(exprType).getUnqualifiedType();
- if (isa<ObjCObjectPointerType>(canCastType) &&
- castType.getObjCLifetime() == Qualifiers::OCL_Weak &&
- canExprType->isObjCObjectPointerType()) {
- if (const ObjCObjectPointerType *ObjT =
- canExprType->getAs<ObjCObjectPointerType>())
- if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl())
- return !ObjI->isArcWeakrefUnavailable();
- }
- return true;
- }
- /// Look for an ObjCReclaimReturnedObject cast and destroy it.
- static Expr *maybeUndoReclaimObject(Expr *e) {
- Expr *curExpr = e, *prevExpr = nullptr;
- // Walk down the expression until we hit an implicit cast of kind
- // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
- while (true) {
- if (auto *pe = dyn_cast<ParenExpr>(curExpr)) {
- prevExpr = curExpr;
- curExpr = pe->getSubExpr();
- continue;
- }
- if (auto *ce = dyn_cast<CastExpr>(curExpr)) {
- if (auto *ice = dyn_cast<ImplicitCastExpr>(ce))
- if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
- if (!prevExpr)
- return ice->getSubExpr();
- if (auto *pe = dyn_cast<ParenExpr>(prevExpr))
- pe->setSubExpr(ice->getSubExpr());
- else
- cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr());
- return e;
- }
- prevExpr = curExpr;
- curExpr = ce->getSubExpr();
- continue;
- }
- // Break out of the loop if curExpr is neither a Paren nor a Cast.
- break;
- }
- return e;
- }
- ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
- ObjCBridgeCastKind Kind,
- SourceLocation BridgeKeywordLoc,
- TypeSourceInfo *TSInfo,
- Expr *SubExpr) {
- ExprResult SubResult = UsualUnaryConversions(SubExpr);
- if (SubResult.isInvalid()) return ExprError();
- SubExpr = SubResult.get();
- QualType T = TSInfo->getType();
- QualType FromType = SubExpr->getType();
- CastKind CK;
- bool MustConsume = false;
- if (T->isDependentType() || SubExpr->isTypeDependent()) {
- // Okay: we'll build a dependent expression type.
- CK = CK_Dependent;
- } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
- // Casting CF -> id
- CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast
- : CK_CPointerToObjCPointerCast);
- switch (Kind) {
- case OBC_Bridge:
- break;
- case OBC_BridgeRetained: {
- bool br = isKnownName("CFBridgingRelease");
- Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
- << 2
- << FromType
- << (T->isBlockPointerType()? 1 : 0)
- << T
- << SubExpr->getSourceRange()
- << Kind;
- Diag(BridgeKeywordLoc, diag::note_arc_bridge)
- << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
- Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
- << FromType << br
- << FixItHint::CreateReplacement(BridgeKeywordLoc,
- br ? "CFBridgingRelease "
- : "__bridge_transfer ");
- Kind = OBC_Bridge;
- break;
- }
- case OBC_BridgeTransfer:
- // We must consume the Objective-C object produced by the cast.
- MustConsume = true;
- break;
- }
- } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
- // Okay: id -> CF
- CK = CK_BitCast;
- switch (Kind) {
- case OBC_Bridge:
- // Reclaiming a value that's going to be __bridge-casted to CF
- // is very dangerous, so we don't do it.
- SubExpr = maybeUndoReclaimObject(SubExpr);
- break;
- case OBC_BridgeRetained:
- // Produce the object before casting it.
- SubExpr = ImplicitCastExpr::Create(Context, FromType, CK_ARCProduceObject,
- SubExpr, nullptr, VK_PRValue,
- FPOptionsOverride());
- break;
- case OBC_BridgeTransfer: {
- bool br = isKnownName("CFBridgingRetain");
- Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
- << (FromType->isBlockPointerType()? 1 : 0)
- << FromType
- << 2
- << T
- << SubExpr->getSourceRange()
- << Kind;
- Diag(BridgeKeywordLoc, diag::note_arc_bridge)
- << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
- Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
- << T << br
- << FixItHint::CreateReplacement(BridgeKeywordLoc,
- br ? "CFBridgingRetain " : "__bridge_retained");
- Kind = OBC_Bridge;
- break;
- }
- }
- } else {
- Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
- << FromType << T << Kind
- << SubExpr->getSourceRange()
- << TSInfo->getTypeLoc().getSourceRange();
- return ExprError();
- }
- Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK,
- BridgeKeywordLoc,
- TSInfo, SubExpr);
- if (MustConsume) {
- Cleanup.setExprNeedsCleanups(true);
- Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result,
- nullptr, VK_PRValue, FPOptionsOverride());
- }
- return Result;
- }
- ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
- SourceLocation LParenLoc,
- ObjCBridgeCastKind Kind,
- SourceLocation BridgeKeywordLoc,
- ParsedType Type,
- SourceLocation RParenLoc,
- Expr *SubExpr) {
- TypeSourceInfo *TSInfo = nullptr;
- QualType T = GetTypeFromParser(Type, &TSInfo);
- if (Kind == OBC_Bridge)
- CheckTollFreeBridgeCast(T, SubExpr);
- if (!TSInfo)
- TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
- return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo,
- SubExpr);
- }
|