123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820 |
- //===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
- //
- // 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 @property and
- // @synthesize declarations.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Sema/SemaInternal.h"
- #include "clang/AST/ASTMutationListener.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/ExprObjC.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Lex/Lexer.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Sema/Initialization.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/SmallString.h"
- using namespace clang;
- //===----------------------------------------------------------------------===//
- // Grammar actions.
- //===----------------------------------------------------------------------===//
- /// getImpliedARCOwnership - Given a set of property attributes and a
- /// type, infer an expected lifetime. The type's ownership qualification
- /// is not considered.
- ///
- /// Returns OCL_None if the attributes as stated do not imply an ownership.
- /// Never returns OCL_Autoreleasing.
- static Qualifiers::ObjCLifetime
- getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) {
- // retain, strong, copy, weak, and unsafe_unretained are only legal
- // on properties of retainable pointer type.
- if (attrs &
- (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong |
- ObjCPropertyAttribute::kind_copy)) {
- return Qualifiers::OCL_Strong;
- } else if (attrs & ObjCPropertyAttribute::kind_weak) {
- return Qualifiers::OCL_Weak;
- } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) {
- return Qualifiers::OCL_ExplicitNone;
- }
- // assign can appear on other types, so we have to check the
- // property type.
- if (attrs & ObjCPropertyAttribute::kind_assign &&
- type->isObjCRetainableType()) {
- return Qualifiers::OCL_ExplicitNone;
- }
- return Qualifiers::OCL_None;
- }
- /// Check the internal consistency of a property declaration with
- /// an explicit ownership qualifier.
- static void checkPropertyDeclWithOwnership(Sema &S,
- ObjCPropertyDecl *property) {
- if (property->isInvalidDecl()) return;
- ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes();
- Qualifiers::ObjCLifetime propertyLifetime
- = property->getType().getObjCLifetime();
- assert(propertyLifetime != Qualifiers::OCL_None);
- Qualifiers::ObjCLifetime expectedLifetime
- = getImpliedARCOwnership(propertyKind, property->getType());
- if (!expectedLifetime) {
- // We have a lifetime qualifier but no dominating property
- // attribute. That's okay, but restore reasonable invariants by
- // setting the property attribute according to the lifetime
- // qualifier.
- ObjCPropertyAttribute::Kind attr;
- if (propertyLifetime == Qualifiers::OCL_Strong) {
- attr = ObjCPropertyAttribute::kind_strong;
- } else if (propertyLifetime == Qualifiers::OCL_Weak) {
- attr = ObjCPropertyAttribute::kind_weak;
- } else {
- assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
- attr = ObjCPropertyAttribute::kind_unsafe_unretained;
- }
- property->setPropertyAttributes(attr);
- return;
- }
- if (propertyLifetime == expectedLifetime) return;
- property->setInvalidDecl();
- S.Diag(property->getLocation(),
- diag::err_arc_inconsistent_property_ownership)
- << property->getDeclName()
- << expectedLifetime
- << propertyLifetime;
- }
- /// Check this Objective-C property against a property declared in the
- /// given protocol.
- static void
- CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
- ObjCProtocolDecl *Proto,
- llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {
- // Have we seen this protocol before?
- if (!Known.insert(Proto).second)
- return;
- // Look for a property with the same name.
- if (ObjCPropertyDecl *ProtoProp = Proto->getProperty(
- Prop->getIdentifier(), Prop->isInstanceProperty())) {
- S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true);
- return;
- }
- // Check this property against any protocols we inherit.
- for (auto *P : Proto->protocols())
- CheckPropertyAgainstProtocol(S, Prop, P, Known);
- }
- static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {
- // In GC mode, just look for the __weak qualifier.
- if (S.getLangOpts().getGC() != LangOptions::NonGC) {
- if (T.isObjCGCWeak())
- return ObjCPropertyAttribute::kind_weak;
- // In ARC/MRC, look for an explicit ownership qualifier.
- // For some reason, this only applies to __weak.
- } else if (auto ownership = T.getObjCLifetime()) {
- switch (ownership) {
- case Qualifiers::OCL_Weak:
- return ObjCPropertyAttribute::kind_weak;
- case Qualifiers::OCL_Strong:
- return ObjCPropertyAttribute::kind_strong;
- case Qualifiers::OCL_ExplicitNone:
- return ObjCPropertyAttribute::kind_unsafe_unretained;
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_None:
- return 0;
- }
- llvm_unreachable("bad qualifier");
- }
- return 0;
- }
- static const unsigned OwnershipMask =
- (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak |
- ObjCPropertyAttribute::kind_strong |
- ObjCPropertyAttribute::kind_unsafe_unretained);
- static unsigned getOwnershipRule(unsigned attr) {
- unsigned result = attr & OwnershipMask;
- // From an ownership perspective, assign and unsafe_unretained are
- // identical; make sure one also implies the other.
- if (result & (ObjCPropertyAttribute::kind_assign |
- ObjCPropertyAttribute::kind_unsafe_unretained)) {
- result |= ObjCPropertyAttribute::kind_assign |
- ObjCPropertyAttribute::kind_unsafe_unretained;
- }
- return result;
- }
- Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
- SourceLocation LParenLoc,
- FieldDeclarator &FD,
- ObjCDeclSpec &ODS,
- Selector GetterSel,
- Selector SetterSel,
- tok::ObjCKeywordKind MethodImplKind,
- DeclContext *lexicalDC) {
- unsigned Attributes = ODS.getPropertyAttributes();
- FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) !=
- 0);
- TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
- QualType T = TSI->getType();
- if (!getOwnershipRule(Attributes)) {
- Attributes |= deducePropertyOwnershipFromType(*this, T);
- }
- bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) ||
- // default is readwrite!
- !(Attributes & ObjCPropertyAttribute::kind_readonly));
- // Proceed with constructing the ObjCPropertyDecls.
- ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
- ObjCPropertyDecl *Res = nullptr;
- if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- if (CDecl->IsClassExtension()) {
- Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
- FD,
- GetterSel, ODS.getGetterNameLoc(),
- SetterSel, ODS.getSetterNameLoc(),
- isReadWrite, Attributes,
- ODS.getPropertyAttributes(),
- T, TSI, MethodImplKind);
- if (!Res)
- return nullptr;
- }
- }
- if (!Res) {
- Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
- GetterSel, ODS.getGetterNameLoc(), SetterSel,
- ODS.getSetterNameLoc(), isReadWrite, Attributes,
- ODS.getPropertyAttributes(), T, TSI,
- MethodImplKind);
- if (lexicalDC)
- Res->setLexicalDeclContext(lexicalDC);
- }
- // Validate the attributes on the @property.
- CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
- (isa<ObjCInterfaceDecl>(ClassDecl) ||
- isa<ObjCProtocolDecl>(ClassDecl)));
- // Check consistency if the type has explicit ownership qualification.
- if (Res->getType().getObjCLifetime())
- checkPropertyDeclWithOwnership(*this, Res);
- llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
- if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- // For a class, compare the property against a property in our superclass.
- bool FoundInSuper = false;
- ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
- while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
- if (ObjCPropertyDecl *SuperProp = Super->getProperty(
- Res->getIdentifier(), Res->isInstanceProperty())) {
- DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
- FoundInSuper = true;
- break;
- }
- CurrentInterfaceDecl = Super;
- }
- if (FoundInSuper) {
- // Also compare the property against a property in our protocols.
- for (auto *P : CurrentInterfaceDecl->protocols()) {
- CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
- }
- } else {
- // Slower path: look in all protocols we referenced.
- for (auto *P : IFace->all_referenced_protocols()) {
- CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
- }
- }
- } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- // We don't check if class extension. Because properties in class extension
- // are meant to override some of the attributes and checking has already done
- // when property in class extension is constructed.
- if (!Cat->IsClassExtension())
- for (auto *P : Cat->protocols())
- CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
- } else {
- ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
- for (auto *P : Proto->protocols())
- CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
- }
- ActOnDocumentableDecl(Res);
- return Res;
- }
- static ObjCPropertyAttribute::Kind
- makePropertyAttributesAsWritten(unsigned Attributes) {
- unsigned attributesAsWritten = 0;
- if (Attributes & ObjCPropertyAttribute::kind_readonly)
- attributesAsWritten |= ObjCPropertyAttribute::kind_readonly;
- if (Attributes & ObjCPropertyAttribute::kind_readwrite)
- attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite;
- if (Attributes & ObjCPropertyAttribute::kind_getter)
- attributesAsWritten |= ObjCPropertyAttribute::kind_getter;
- if (Attributes & ObjCPropertyAttribute::kind_setter)
- attributesAsWritten |= ObjCPropertyAttribute::kind_setter;
- if (Attributes & ObjCPropertyAttribute::kind_assign)
- attributesAsWritten |= ObjCPropertyAttribute::kind_assign;
- if (Attributes & ObjCPropertyAttribute::kind_retain)
- attributesAsWritten |= ObjCPropertyAttribute::kind_retain;
- if (Attributes & ObjCPropertyAttribute::kind_strong)
- attributesAsWritten |= ObjCPropertyAttribute::kind_strong;
- if (Attributes & ObjCPropertyAttribute::kind_weak)
- attributesAsWritten |= ObjCPropertyAttribute::kind_weak;
- if (Attributes & ObjCPropertyAttribute::kind_copy)
- attributesAsWritten |= ObjCPropertyAttribute::kind_copy;
- if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
- attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained;
- if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
- attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic;
- if (Attributes & ObjCPropertyAttribute::kind_atomic)
- attributesAsWritten |= ObjCPropertyAttribute::kind_atomic;
- if (Attributes & ObjCPropertyAttribute::kind_class)
- attributesAsWritten |= ObjCPropertyAttribute::kind_class;
- if (Attributes & ObjCPropertyAttribute::kind_direct)
- attributesAsWritten |= ObjCPropertyAttribute::kind_direct;
- return (ObjCPropertyAttribute::Kind)attributesAsWritten;
- }
- static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
- SourceLocation LParenLoc, SourceLocation &Loc) {
- if (LParenLoc.isMacroID())
- return false;
- SourceManager &SM = Context.getSourceManager();
- std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(LParenLoc);
- // Try to load the file buffer.
- bool invalidTemp = false;
- StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
- if (invalidTemp)
- return false;
- const char *tokenBegin = file.data() + locInfo.second;
- // Lex from the start of the given location.
- Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
- Context.getLangOpts(),
- file.begin(), tokenBegin, file.end());
- Token Tok;
- do {
- lexer.LexFromRawLexer(Tok);
- if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {
- Loc = Tok.getLocation();
- return true;
- }
- } while (Tok.isNot(tok::r_paren));
- return false;
- }
- /// Check for a mismatch in the atomicity of the given properties.
- static void checkAtomicPropertyMismatch(Sema &S,
- ObjCPropertyDecl *OldProperty,
- ObjCPropertyDecl *NewProperty,
- bool PropagateAtomicity) {
- // If the atomicity of both matches, we're done.
- bool OldIsAtomic = (OldProperty->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_nonatomic) == 0;
- bool NewIsAtomic = (NewProperty->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_nonatomic) == 0;
- if (OldIsAtomic == NewIsAtomic) return;
- // Determine whether the given property is readonly and implicitly
- // atomic.
- auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
- // Is it readonly?
- auto Attrs = Property->getPropertyAttributes();
- if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0)
- return false;
- // Is it nonatomic?
- if (Attrs & ObjCPropertyAttribute::kind_nonatomic)
- return false;
- // Was 'atomic' specified directly?
- if (Property->getPropertyAttributesAsWritten() &
- ObjCPropertyAttribute::kind_atomic)
- return false;
- return true;
- };
- // If we're allowed to propagate atomicity, and the new property did
- // not specify atomicity at all, propagate.
- const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic |
- ObjCPropertyAttribute::kind_nonatomic);
- if (PropagateAtomicity &&
- ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {
- unsigned Attrs = NewProperty->getPropertyAttributes();
- Attrs = Attrs & ~AtomicityMask;
- if (OldIsAtomic)
- Attrs |= ObjCPropertyAttribute::kind_atomic;
- else
- Attrs |= ObjCPropertyAttribute::kind_nonatomic;
- NewProperty->overwritePropertyAttributes(Attrs);
- return;
- }
- // One of the properties is atomic; if it's a readonly property, and
- // 'atomic' wasn't explicitly specified, we're okay.
- if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) ||
- (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty)))
- return;
- // Diagnose the conflict.
- const IdentifierInfo *OldContextName;
- auto *OldDC = OldProperty->getDeclContext();
- if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC))
- OldContextName = Category->getClassInterface()->getIdentifier();
- else
- OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier();
- S.Diag(NewProperty->getLocation(), diag::warn_property_attribute)
- << NewProperty->getDeclName() << "atomic"
- << OldContextName;
- S.Diag(OldProperty->getLocation(), diag::note_property_declare);
- }
- ObjCPropertyDecl *
- Sema::HandlePropertyInClassExtension(Scope *S,
- SourceLocation AtLoc,
- SourceLocation LParenLoc,
- FieldDeclarator &FD,
- Selector GetterSel,
- SourceLocation GetterNameLoc,
- Selector SetterSel,
- SourceLocation SetterNameLoc,
- const bool isReadWrite,
- unsigned &Attributes,
- const unsigned AttributesAsWritten,
- QualType T,
- TypeSourceInfo *TSI,
- tok::ObjCKeywordKind MethodImplKind) {
- ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext);
- // Diagnose if this property is already in continuation class.
- DeclContext *DC = CurContext;
- IdentifierInfo *PropertyId = FD.D.getIdentifier();
- ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
- // We need to look in the @interface to see if the @property was
- // already declared.
- if (!CCPrimary) {
- Diag(CDecl->getLocation(), diag::err_continuation_class);
- return nullptr;
- }
- bool isClassProperty =
- (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
- (Attributes & ObjCPropertyAttribute::kind_class);
- // Find the property in the extended class's primary class or
- // extensions.
- ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(
- PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));
- // If we found a property in an extension, complain.
- if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
- Diag(AtLoc, diag::err_duplicate_property);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- return nullptr;
- }
- // Check for consistency with the previous declaration, if there is one.
- if (PIDecl) {
- // A readonly property declared in the primary class can be refined
- // by adding a readwrite property within an extension.
- // Anything else is an error.
- if (!(PIDecl->isReadOnly() && isReadWrite)) {
- // Tailor the diagnostics for the common case where a readwrite
- // property is declared both in the @interface and the continuation.
- // This is a common error where the user often intended the original
- // declaration to be readonly.
- unsigned diag =
- (Attributes & ObjCPropertyAttribute::kind_readwrite) &&
- (PIDecl->getPropertyAttributesAsWritten() &
- ObjCPropertyAttribute::kind_readwrite)
- ? diag::err_use_continuation_class_redeclaration_readwrite
- : diag::err_use_continuation_class;
- Diag(AtLoc, diag)
- << CCPrimary->getDeclName();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- return nullptr;
- }
- // Check for consistency of getters.
- if (PIDecl->getGetterName() != GetterSel) {
- // If the getter was written explicitly, complain.
- if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) {
- Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
- << PIDecl->getGetterName() << GetterSel;
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- // Always adopt the getter from the original declaration.
- GetterSel = PIDecl->getGetterName();
- Attributes |= ObjCPropertyAttribute::kind_getter;
- }
- // Check consistency of ownership.
- unsigned ExistingOwnership
- = getOwnershipRule(PIDecl->getPropertyAttributes());
- unsigned NewOwnership = getOwnershipRule(Attributes);
- if (ExistingOwnership && NewOwnership != ExistingOwnership) {
- // If the ownership was written explicitly, complain.
- if (getOwnershipRule(AttributesAsWritten)) {
- Diag(AtLoc, diag::warn_property_attr_mismatch);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- // Take the ownership from the original property.
- Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership;
- }
- // If the redeclaration is 'weak' but the original property is not,
- if ((Attributes & ObjCPropertyAttribute::kind_weak) &&
- !(PIDecl->getPropertyAttributesAsWritten() &
- ObjCPropertyAttribute::kind_weak) &&
- PIDecl->getType()->getAs<ObjCObjectPointerType>() &&
- PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {
- Diag(AtLoc, diag::warn_property_implicitly_mismatched);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- }
- // Create a new ObjCPropertyDecl with the DeclContext being
- // the class extension.
- ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
- FD, GetterSel, GetterNameLoc,
- SetterSel, SetterNameLoc,
- isReadWrite,
- Attributes, AttributesAsWritten,
- T, TSI, MethodImplKind, DC);
- // If there was no declaration of a property with the same name in
- // the primary class, we're done.
- if (!PIDecl) {
- ProcessPropertyDecl(PDecl);
- return PDecl;
- }
- if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
- bool IncompatibleObjC = false;
- QualType ConvertedType;
- // Relax the strict type matching for property type in continuation class.
- // Allow property object type of continuation class to be different as long
- // as it narrows the object type in its primary class property. Note that
- // this conversion is safe only because the wider type is for a 'readonly'
- // property in primary class and 'narrowed' type for a 'readwrite' property
- // in continuation class.
- QualType PrimaryClassPropertyT = Context.getCanonicalType(PIDecl->getType());
- QualType ClassExtPropertyT = Context.getCanonicalType(PDecl->getType());
- if (!isa<ObjCObjectPointerType>(PrimaryClassPropertyT) ||
- !isa<ObjCObjectPointerType>(ClassExtPropertyT) ||
- (!isObjCPointerConversion(ClassExtPropertyT, PrimaryClassPropertyT,
- ConvertedType, IncompatibleObjC))
- || IncompatibleObjC) {
- Diag(AtLoc,
- diag::err_type_mismatch_continuation_class) << PDecl->getType();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- return nullptr;
- }
- }
- // Check that atomicity of property in class extension matches the previous
- // declaration.
- checkAtomicPropertyMismatch(*this, PIDecl, PDecl, true);
- // Make sure getter/setter are appropriately synthesized.
- ProcessPropertyDecl(PDecl);
- return PDecl;
- }
- ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
- ObjCContainerDecl *CDecl,
- SourceLocation AtLoc,
- SourceLocation LParenLoc,
- FieldDeclarator &FD,
- Selector GetterSel,
- SourceLocation GetterNameLoc,
- Selector SetterSel,
- SourceLocation SetterNameLoc,
- const bool isReadWrite,
- const unsigned Attributes,
- const unsigned AttributesAsWritten,
- QualType T,
- TypeSourceInfo *TInfo,
- tok::ObjCKeywordKind MethodImplKind,
- DeclContext *lexicalDC){
- IdentifierInfo *PropertyId = FD.D.getIdentifier();
- // Property defaults to 'assign' if it is readwrite, unless this is ARC
- // and the type is retainable.
- bool isAssign;
- if (Attributes & (ObjCPropertyAttribute::kind_assign |
- ObjCPropertyAttribute::kind_unsafe_unretained)) {
- isAssign = true;
- } else if (getOwnershipRule(Attributes) || !isReadWrite) {
- isAssign = false;
- } else {
- isAssign = (!getLangOpts().ObjCAutoRefCount ||
- !T->isObjCRetainableType());
- }
- // Issue a warning if property is 'assign' as default and its
- // object, which is gc'able conforms to NSCopying protocol
- if (getLangOpts().getGC() != LangOptions::NonGC && isAssign &&
- !(Attributes & ObjCPropertyAttribute::kind_assign)) {
- if (const ObjCObjectPointerType *ObjPtrTy =
- T->getAs<ObjCObjectPointerType>()) {
- ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
- if (IDecl)
- if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
- if (IDecl->ClassImplementsProtocol(PNSCopying, true))
- Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
- }
- }
- if (T->isObjCObjectType()) {
- SourceLocation StarLoc = TInfo->getTypeLoc().getEndLoc();
- StarLoc = getLocForEndOfToken(StarLoc);
- Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
- << FixItHint::CreateInsertion(StarLoc, "*");
- T = Context.getObjCObjectPointerType(T);
- SourceLocation TLoc = TInfo->getTypeLoc().getBeginLoc();
- TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);
- }
- DeclContext *DC = CDecl;
- ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
- PropertyId, AtLoc,
- LParenLoc, T, TInfo);
- bool isClassProperty =
- (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
- (Attributes & ObjCPropertyAttribute::kind_class);
- // Class property and instance property can have the same name.
- if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
- DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
- Diag(PDecl->getLocation(), diag::err_duplicate_property);
- Diag(prevDecl->getLocation(), diag::note_property_declare);
- PDecl->setInvalidDecl();
- }
- else {
- DC->addDecl(PDecl);
- if (lexicalDC)
- PDecl->setLexicalDeclContext(lexicalDC);
- }
- if (T->isArrayType() || T->isFunctionType()) {
- Diag(AtLoc, diag::err_property_type) << T;
- PDecl->setInvalidDecl();
- }
- ProcessDeclAttributes(S, PDecl, FD.D);
- // Regardless of setter/getter attribute, we save the default getter/setter
- // selector names in anticipation of declaration of setter/getter methods.
- PDecl->setGetterName(GetterSel, GetterNameLoc);
- PDecl->setSetterName(SetterSel, SetterNameLoc);
- PDecl->setPropertyAttributesAsWritten(
- makePropertyAttributesAsWritten(AttributesAsWritten));
- if (Attributes & ObjCPropertyAttribute::kind_readonly)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
- if (Attributes & ObjCPropertyAttribute::kind_getter)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
- if (Attributes & ObjCPropertyAttribute::kind_setter)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
- if (isReadWrite)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
- if (Attributes & ObjCPropertyAttribute::kind_retain)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
- if (Attributes & ObjCPropertyAttribute::kind_strong)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
- if (Attributes & ObjCPropertyAttribute::kind_weak)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
- if (Attributes & ObjCPropertyAttribute::kind_copy)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
- if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
- if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
- // In the semantic attributes, one of nonatomic or atomic is always set.
- if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
- else
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
- // 'unsafe_unretained' is alias for 'assign'.
- if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
- if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
- if (MethodImplKind == tok::objc_required)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
- else if (MethodImplKind == tok::objc_optional)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
- if (Attributes & ObjCPropertyAttribute::kind_nullability)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
- if (Attributes & ObjCPropertyAttribute::kind_null_resettable)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
- if (Attributes & ObjCPropertyAttribute::kind_class)
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class);
- if ((Attributes & ObjCPropertyAttribute::kind_direct) ||
- CDecl->hasAttr<ObjCDirectMembersAttr>()) {
- if (isa<ObjCProtocolDecl>(CDecl)) {
- Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
- } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
- PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
- } else {
- Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
- << PDecl->getDeclName();
- }
- }
- return PDecl;
- }
- static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
- ObjCPropertyDecl *property,
- ObjCIvarDecl *ivar) {
- if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
- QualType ivarType = ivar->getType();
- Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
- // The lifetime implied by the property's attributes.
- Qualifiers::ObjCLifetime propertyLifetime =
- getImpliedARCOwnership(property->getPropertyAttributes(),
- property->getType());
- // We're fine if they match.
- if (propertyLifetime == ivarLifetime) return;
- // None isn't a valid lifetime for an object ivar in ARC, and
- // __autoreleasing is never valid; don't diagnose twice.
- if ((ivarLifetime == Qualifiers::OCL_None &&
- S.getLangOpts().ObjCAutoRefCount) ||
- ivarLifetime == Qualifiers::OCL_Autoreleasing)
- return;
- // If the ivar is private, and it's implicitly __unsafe_unretained
- // because of its type, then pretend it was actually implicitly
- // __strong. This is only sound because we're processing the
- // property implementation before parsing any method bodies.
- if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
- propertyLifetime == Qualifiers::OCL_Strong &&
- ivar->getAccessControl() == ObjCIvarDecl::Private) {
- SplitQualType split = ivarType.split();
- if (split.Quals.hasObjCLifetime()) {
- assert(ivarType->isObjCARCImplicitlyUnretainedType());
- split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
- ivarType = S.Context.getQualifiedType(split);
- ivar->setType(ivarType);
- return;
- }
- }
- switch (propertyLifetime) {
- case Qualifiers::OCL_Strong:
- S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
- << property->getDeclName()
- << ivar->getDeclName()
- << ivarLifetime;
- break;
- case Qualifiers::OCL_Weak:
- S.Diag(ivar->getLocation(), diag::err_weak_property)
- << property->getDeclName()
- << ivar->getDeclName();
- break;
- case Qualifiers::OCL_ExplicitNone:
- S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
- << property->getDeclName() << ivar->getDeclName()
- << ((property->getPropertyAttributesAsWritten() &
- ObjCPropertyAttribute::kind_assign) != 0);
- break;
- case Qualifiers::OCL_Autoreleasing:
- llvm_unreachable("properties cannot be autoreleasing");
- case Qualifiers::OCL_None:
- // Any other property should be ignored.
- return;
- }
- S.Diag(property->getLocation(), diag::note_property_declare);
- if (propertyImplLoc.isValid())
- S.Diag(propertyImplLoc, diag::note_property_synthesize);
- }
- /// setImpliedPropertyAttributeForReadOnlyProperty -
- /// This routine evaludates life-time attributes for a 'readonly'
- /// property with no known lifetime of its own, using backing
- /// 'ivar's attribute, if any. If no backing 'ivar', property's
- /// life-time is assumed 'strong'.
- static void setImpliedPropertyAttributeForReadOnlyProperty(
- ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
- Qualifiers::ObjCLifetime propertyLifetime =
- getImpliedARCOwnership(property->getPropertyAttributes(),
- property->getType());
- if (propertyLifetime != Qualifiers::OCL_None)
- return;
- if (!ivar) {
- // if no backing ivar, make property 'strong'.
- property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
- return;
- }
- // property assumes owenership of backing ivar.
- QualType ivarType = ivar->getType();
- Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
- if (ivarLifetime == Qualifiers::OCL_Strong)
- property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
- else if (ivarLifetime == Qualifiers::OCL_Weak)
- property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
- }
- static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
- ObjCPropertyAttribute::Kind Kind) {
- return (Attr1 & Kind) != (Attr2 & Kind);
- }
- static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,
- unsigned Kinds) {
- return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);
- }
- /// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate
- /// property declaration that should be synthesised in all of the inherited
- /// protocols. It also diagnoses properties declared in inherited protocols with
- /// mismatched types or attributes, since any of them can be candidate for
- /// synthesis.
- static ObjCPropertyDecl *
- SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
- ObjCInterfaceDecl *ClassDecl,
- ObjCPropertyDecl *Property) {
- assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&
- "Expected a property from a protocol");
- ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;
- ObjCInterfaceDecl::PropertyDeclOrder Properties;
- for (const auto *PI : ClassDecl->all_referenced_protocols()) {
- if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
- Properties);
- }
- if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {
- while (SDecl) {
- for (const auto *PI : SDecl->all_referenced_protocols()) {
- if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
- Properties);
- }
- SDecl = SDecl->getSuperClass();
- }
- }
- if (Properties.empty())
- return Property;
- ObjCPropertyDecl *OriginalProperty = Property;
- size_t SelectedIndex = 0;
- for (const auto &Prop : llvm::enumerate(Properties)) {
- // Select the 'readwrite' property if such property exists.
- if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {
- Property = Prop.value();
- SelectedIndex = Prop.index();
- }
- }
- if (Property != OriginalProperty) {
- // Check that the old property is compatible with the new one.
- Properties[SelectedIndex] = OriginalProperty;
- }
- QualType RHSType = S.Context.getCanonicalType(Property->getType());
- unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();
- enum MismatchKind {
- IncompatibleType = 0,
- HasNoExpectedAttribute,
- HasUnexpectedAttribute,
- DifferentGetter,
- DifferentSetter
- };
- // Represents a property from another protocol that conflicts with the
- // selected declaration.
- struct MismatchingProperty {
- const ObjCPropertyDecl *Prop;
- MismatchKind Kind;
- StringRef AttributeName;
- };
- SmallVector<MismatchingProperty, 4> Mismatches;
- for (ObjCPropertyDecl *Prop : Properties) {
- // Verify the property attributes.
- unsigned Attr = Prop->getPropertyAttributesAsWritten();
- if (Attr != OriginalAttributes) {
- auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {
- MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute
- : HasUnexpectedAttribute;
- Mismatches.push_back({Prop, Kind, AttributeName});
- };
- // The ownership might be incompatible unless the property has no explicit
- // ownership.
- bool HasOwnership =
- (Attr & (ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong |
- ObjCPropertyAttribute::kind_copy |
- ObjCPropertyAttribute::kind_assign |
- ObjCPropertyAttribute::kind_unsafe_unretained |
- ObjCPropertyAttribute::kind_weak)) != 0;
- if (HasOwnership &&
- isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
- ObjCPropertyAttribute::kind_copy)) {
- Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy");
- continue;
- }
- if (HasOwnership && areIncompatiblePropertyAttributes(
- OriginalAttributes, Attr,
- ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong)) {
- Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong),
- "retain (or strong)");
- continue;
- }
- if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
- ObjCPropertyAttribute::kind_atomic)) {
- Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic");
- continue;
- }
- }
- if (Property->getGetterName() != Prop->getGetterName()) {
- Mismatches.push_back({Prop, DifferentGetter, ""});
- continue;
- }
- if (!Property->isReadOnly() && !Prop->isReadOnly() &&
- Property->getSetterName() != Prop->getSetterName()) {
- Mismatches.push_back({Prop, DifferentSetter, ""});
- continue;
- }
- QualType LHSType = S.Context.getCanonicalType(Prop->getType());
- if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
- bool IncompatibleObjC = false;
- QualType ConvertedType;
- if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
- || IncompatibleObjC) {
- Mismatches.push_back({Prop, IncompatibleType, ""});
- continue;
- }
- }
- }
- if (Mismatches.empty())
- return Property;
- // Diagnose incompability.
- {
- bool HasIncompatibleAttributes = false;
- for (const auto &Note : Mismatches)
- HasIncompatibleAttributes =
- Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;
- // Promote the warning to an error if there are incompatible attributes or
- // incompatible types together with readwrite/readonly incompatibility.
- auto Diag = S.Diag(Property->getLocation(),
- Property != OriginalProperty || HasIncompatibleAttributes
- ? diag::err_protocol_property_mismatch
- : diag::warn_protocol_property_mismatch);
- Diag << Mismatches[0].Kind;
- switch (Mismatches[0].Kind) {
- case IncompatibleType:
- Diag << Property->getType();
- break;
- case HasNoExpectedAttribute:
- case HasUnexpectedAttribute:
- Diag << Mismatches[0].AttributeName;
- break;
- case DifferentGetter:
- Diag << Property->getGetterName();
- break;
- case DifferentSetter:
- Diag << Property->getSetterName();
- break;
- }
- }
- for (const auto &Note : Mismatches) {
- auto Diag =
- S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)
- << Note.Kind;
- switch (Note.Kind) {
- case IncompatibleType:
- Diag << Note.Prop->getType();
- break;
- case HasNoExpectedAttribute:
- case HasUnexpectedAttribute:
- Diag << Note.AttributeName;
- break;
- case DifferentGetter:
- Diag << Note.Prop->getGetterName();
- break;
- case DifferentSetter:
- Diag << Note.Prop->getSetterName();
- break;
- }
- }
- if (AtLoc.isValid())
- S.Diag(AtLoc, diag::note_property_synthesize);
- return Property;
- }
- /// Determine whether any storage attributes were written on the property.
- static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
- ObjCPropertyQueryKind QueryKind) {
- if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;
- // If this is a readwrite property in a class extension that refines
- // a readonly property in the original class definition, check it as
- // well.
- // If it's a readonly property, we're not interested.
- if (Prop->isReadOnly()) return false;
- // Is it declared in an extension?
- auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext());
- if (!Category || !Category->IsClassExtension()) return false;
- // Find the corresponding property in the primary class definition.
- auto OrigClass = Category->getClassInterface();
- for (auto *Found : OrigClass->lookup(Prop->getDeclName())) {
- if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
- return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
- }
- // Look through all of the protocols.
- for (const auto *Proto : OrigClass->all_referenced_protocols()) {
- if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(
- Prop->getIdentifier(), QueryKind))
- return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
- }
- return false;
- }
- /// Create a synthesized property accessor stub inside the \@implementation.
- static ObjCMethodDecl *
- RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,
- ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,
- SourceLocation PropertyLoc) {
- ObjCMethodDecl *Decl = AccessorDecl;
- ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(
- Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),
- PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),
- Decl->getSelector(), Decl->getReturnType(),
- Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),
- Decl->isVariadic(), Decl->isPropertyAccessor(),
- /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(),
- Decl->getImplementationControl(), Decl->hasRelatedResultType());
- ImplDecl->getMethodFamily();
- if (Decl->hasAttrs())
- ImplDecl->setAttrs(Decl->getAttrs());
- ImplDecl->setSelfDecl(Decl->getSelfDecl());
- ImplDecl->setCmdDecl(Decl->getCmdDecl());
- SmallVector<SourceLocation, 1> SelLocs;
- Decl->getSelectorLocs(SelLocs);
- ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);
- ImplDecl->setLexicalDeclContext(Impl);
- ImplDecl->setDefined(false);
- return ImplDecl;
- }
- /// ActOnPropertyImplDecl - This routine performs semantic checks and
- /// builds the AST node for a property implementation declaration; declared
- /// as \@synthesize or \@dynamic.
- ///
- Decl *Sema::ActOnPropertyImplDecl(Scope *S,
- SourceLocation AtLoc,
- SourceLocation PropertyLoc,
- bool Synthesize,
- IdentifierInfo *PropertyId,
- IdentifierInfo *PropertyIvar,
- SourceLocation PropertyIvarLoc,
- ObjCPropertyQueryKind QueryKind) {
- ObjCContainerDecl *ClassImpDecl =
- dyn_cast<ObjCContainerDecl>(CurContext);
- // Make sure we have a context for the property implementation declaration.
- if (!ClassImpDecl) {
- Diag(AtLoc, diag::err_missing_property_context);
- return nullptr;
- }
- if (PropertyIvarLoc.isInvalid())
- PropertyIvarLoc = PropertyLoc;
- SourceLocation PropertyDiagLoc = PropertyLoc;
- if (PropertyDiagLoc.isInvalid())
- PropertyDiagLoc = ClassImpDecl->getBeginLoc();
- ObjCPropertyDecl *property = nullptr;
- ObjCInterfaceDecl *IDecl = nullptr;
- // Find the class or category class where this property must have
- // a declaration.
- ObjCImplementationDecl *IC = nullptr;
- ObjCCategoryImplDecl *CatImplClass = nullptr;
- if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
- IDecl = IC->getClassInterface();
- // We always synthesize an interface for an implementation
- // without an interface decl. So, IDecl is always non-zero.
- assert(IDecl &&
- "ActOnPropertyImplDecl - @implementation without @interface");
- // Look for this property declaration in the @implementation's @interface
- property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);
- if (!property) {
- Diag(PropertyLoc, diag::err_bad_property_decl) << IDecl->getDeclName();
- return nullptr;
- }
- if (property->isClassProperty() && Synthesize) {
- Diag(PropertyLoc, diag::err_synthesize_on_class_property) << PropertyId;
- return nullptr;
- }
- unsigned PIkind = property->getPropertyAttributesAsWritten();
- if ((PIkind & (ObjCPropertyAttribute::kind_atomic |
- ObjCPropertyAttribute::kind_nonatomic)) == 0) {
- if (AtLoc.isValid())
- Diag(AtLoc, diag::warn_implicit_atomic_property);
- else
- Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property);
- Diag(property->getLocation(), diag::note_property_declare);
- }
- if (const ObjCCategoryDecl *CD =
- dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
- if (!CD->IsClassExtension()) {
- Diag(PropertyLoc, diag::err_category_property) << CD->getDeclName();
- Diag(property->getLocation(), diag::note_property_declare);
- return nullptr;
- }
- }
- if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) &&
- property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) {
- bool ReadWriteProperty = false;
- // Search into the class extensions and see if 'readonly property is
- // redeclared 'readwrite', then no warning is to be issued.
- for (auto *Ext : IDecl->known_extensions()) {
- DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
- if (auto *ExtProp = R.find_first<ObjCPropertyDecl>()) {
- PIkind = ExtProp->getPropertyAttributesAsWritten();
- if (PIkind & ObjCPropertyAttribute::kind_readwrite) {
- ReadWriteProperty = true;
- break;
- }
- }
- }
- if (!ReadWriteProperty) {
- Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
- << property;
- SourceLocation readonlyLoc;
- if (LocPropertyAttribute(Context, "readonly",
- property->getLParenLoc(), readonlyLoc)) {
- SourceLocation endLoc =
- readonlyLoc.getLocWithOffset(strlen("readonly")-1);
- SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
- Diag(property->getLocation(),
- diag::note_auto_readonly_iboutlet_fixup_suggest) <<
- FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
- }
- }
- }
- if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
- property = SelectPropertyForSynthesisFromProtocols(*this, AtLoc, IDecl,
- property);
- } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
- if (Synthesize) {
- Diag(AtLoc, diag::err_synthesize_category_decl);
- return nullptr;
- }
- IDecl = CatImplClass->getClassInterface();
- if (!IDecl) {
- Diag(AtLoc, diag::err_missing_property_interface);
- return nullptr;
- }
- ObjCCategoryDecl *Category =
- IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
- // If category for this implementation not found, it is an error which
- // has already been reported eralier.
- if (!Category)
- return nullptr;
- // Look for this property declaration in @implementation's category
- property = Category->FindPropertyDeclaration(PropertyId, QueryKind);
- if (!property) {
- Diag(PropertyLoc, diag::err_bad_category_property_decl)
- << Category->getDeclName();
- return nullptr;
- }
- } else {
- Diag(AtLoc, diag::err_bad_property_context);
- return nullptr;
- }
- ObjCIvarDecl *Ivar = nullptr;
- bool CompleteTypeErr = false;
- bool compat = true;
- // Check that we have a valid, previously declared ivar for @synthesize
- if (Synthesize) {
- // @synthesize
- if (!PropertyIvar)
- PropertyIvar = PropertyId;
- // Check that this is a previously declared 'ivar' in 'IDecl' interface
- ObjCInterfaceDecl *ClassDeclared;
- Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
- QualType PropType = property->getType();
- QualType PropertyIvarType = PropType.getNonReferenceType();
- if (RequireCompleteType(PropertyDiagLoc, PropertyIvarType,
- diag::err_incomplete_synthesized_property,
- property->getDeclName())) {
- Diag(property->getLocation(), diag::note_property_declare);
- CompleteTypeErr = true;
- }
- if (getLangOpts().ObjCAutoRefCount &&
- (property->getPropertyAttributesAsWritten() &
- ObjCPropertyAttribute::kind_readonly) &&
- PropertyIvarType->isObjCRetainableType()) {
- setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
- }
- ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes();
- bool isARCWeak = false;
- if (kind & ObjCPropertyAttribute::kind_weak) {
- // Add GC __weak to the ivar type if the property is weak.
- if (getLangOpts().getGC() != LangOptions::NonGC) {
- assert(!getLangOpts().ObjCAutoRefCount);
- if (PropertyIvarType.isObjCGCStrong()) {
- Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);
- Diag(property->getLocation(), diag::note_property_declare);
- } else {
- PropertyIvarType =
- Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
- }
- // Otherwise, check whether ARC __weak is enabled and works with
- // the property type.
- } else {
- if (!getLangOpts().ObjCWeak) {
- // Only complain here when synthesizing an ivar.
- if (!Ivar) {
- Diag(PropertyDiagLoc,
- getLangOpts().ObjCWeakRuntime
- ? diag::err_synthesizing_arc_weak_property_disabled
- : diag::err_synthesizing_arc_weak_property_no_runtime);
- Diag(property->getLocation(), diag::note_property_declare);
- }
- CompleteTypeErr = true; // suppress later diagnostics about the ivar
- } else {
- isARCWeak = true;
- if (const ObjCObjectPointerType *ObjT =
- PropertyIvarType->getAs<ObjCObjectPointerType>()) {
- const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
- if (ObjI && ObjI->isArcWeakrefUnavailable()) {
- Diag(property->getLocation(),
- diag::err_arc_weak_unavailable_property)
- << PropertyIvarType;
- Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class)
- << ClassImpDecl->getName();
- }
- }
- }
- }
- }
- if (AtLoc.isInvalid()) {
- // Check when default synthesizing a property that there is
- // an ivar matching property name and issue warning; since this
- // is the most common case of not using an ivar used for backing
- // property in non-default synthesis case.
- ObjCInterfaceDecl *ClassDeclared=nullptr;
- ObjCIvarDecl *originalIvar =
- IDecl->lookupInstanceVariable(property->getIdentifier(),
- ClassDeclared);
- if (originalIvar) {
- Diag(PropertyDiagLoc,
- diag::warn_autosynthesis_property_ivar_match)
- << PropertyId << (Ivar == nullptr) << PropertyIvar
- << originalIvar->getIdentifier();
- Diag(property->getLocation(), diag::note_property_declare);
- Diag(originalIvar->getLocation(), diag::note_ivar_decl);
- }
- }
- if (!Ivar) {
- // In ARC, give the ivar a lifetime qualifier based on the
- // property attributes.
- if ((getLangOpts().ObjCAutoRefCount || isARCWeak) &&
- !PropertyIvarType.getObjCLifetime() &&
- PropertyIvarType->isObjCRetainableType()) {
- // It's an error if we have to do this and the user didn't
- // explicitly write an ownership attribute on the property.
- if (!hasWrittenStorageAttribute(property, QueryKind) &&
- !(kind & ObjCPropertyAttribute::kind_strong)) {
- Diag(PropertyDiagLoc,
- diag::err_arc_objc_property_default_assign_on_object);
- Diag(property->getLocation(), diag::note_property_declare);
- } else {
- Qualifiers::ObjCLifetime lifetime =
- getImpliedARCOwnership(kind, PropertyIvarType);
- assert(lifetime && "no lifetime for property?");
- Qualifiers qs;
- qs.addObjCLifetime(lifetime);
- PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
- }
- }
- Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
- PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
- PropertyIvarType, /*TInfo=*/nullptr,
- ObjCIvarDecl::Private,
- (Expr *)nullptr, true);
- if (RequireNonAbstractType(PropertyIvarLoc,
- PropertyIvarType,
- diag::err_abstract_type_in_decl,
- AbstractSynthesizedIvarType)) {
- Diag(property->getLocation(), diag::note_property_declare);
- // An abstract type is as bad as an incomplete type.
- CompleteTypeErr = true;
- }
- if (!CompleteTypeErr) {
- const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
- if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) {
- Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
- << PropertyIvarType;
- CompleteTypeErr = true; // suppress later diagnostics about the ivar
- }
- }
- if (CompleteTypeErr)
- Ivar->setInvalidDecl();
- ClassImpDecl->addDecl(Ivar);
- IDecl->makeDeclVisibleInContext(Ivar);
- if (getLangOpts().ObjCRuntime.isFragile())
- Diag(PropertyDiagLoc, diag::err_missing_property_ivar_decl)
- << PropertyId;
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- } else if (getLangOpts().ObjCRuntime.isNonFragile() &&
- !declaresSameEntity(ClassDeclared, IDecl)) {
- Diag(PropertyDiagLoc, diag::err_ivar_in_superclass_use)
- << property->getDeclName() << Ivar->getDeclName()
- << ClassDeclared->getDeclName();
- Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
- << Ivar << Ivar->getName();
- // Note! I deliberately want it to fall thru so more errors are caught.
- }
- property->setPropertyIvarDecl(Ivar);
- QualType IvarType = Context.getCanonicalType(Ivar->getType());
- // Check that type of property and its ivar are type compatible.
- if (!Context.hasSameType(PropertyIvarType, IvarType)) {
- if (isa<ObjCObjectPointerType>(PropertyIvarType)
- && isa<ObjCObjectPointerType>(IvarType))
- compat =
- Context.canAssignObjCInterfaces(
- PropertyIvarType->getAs<ObjCObjectPointerType>(),
- IvarType->getAs<ObjCObjectPointerType>());
- else {
- compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType,
- IvarType)
- == Compatible);
- }
- if (!compat) {
- Diag(PropertyDiagLoc, diag::err_property_ivar_type)
- << property->getDeclName() << PropType
- << Ivar->getDeclName() << IvarType;
- Diag(Ivar->getLocation(), diag::note_ivar_decl);
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- }
- else {
- // FIXME! Rules for properties are somewhat different that those
- // for assignments. Use a new routine to consolidate all cases;
- // specifically for property redeclarations as well as for ivars.
- QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
- QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
- if (lhsType != rhsType &&
- lhsType->isArithmeticType()) {
- Diag(PropertyDiagLoc, diag::err_property_ivar_type)
- << property->getDeclName() << PropType
- << Ivar->getDeclName() << IvarType;
- Diag(Ivar->getLocation(), diag::note_ivar_decl);
- // Fall thru - see previous comment
- }
- }
- // __weak is explicit. So it works on Canonical type.
- if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOpts().getGC() != LangOptions::NonGC)) {
- Diag(PropertyDiagLoc, diag::err_weak_property)
- << property->getDeclName() << Ivar->getDeclName();
- Diag(Ivar->getLocation(), diag::note_ivar_decl);
- // Fall thru - see previous comment
- }
- // Fall thru - see previous comment
- if ((property->getType()->isObjCObjectPointerType() ||
- PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
- getLangOpts().getGC() != LangOptions::NonGC) {
- Diag(PropertyDiagLoc, diag::err_strong_property)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- }
- if (getLangOpts().ObjCAutoRefCount || isARCWeak ||
- Ivar->getType().getObjCLifetime())
- checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
- } else if (PropertyIvar)
- // @dynamic
- Diag(PropertyDiagLoc, diag::err_dynamic_property_ivar_decl);
- assert (property && "ActOnPropertyImplDecl - property declaration missing");
- ObjCPropertyImplDecl *PIDecl =
- ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
- property,
- (Synthesize ?
- ObjCPropertyImplDecl::Synthesize
- : ObjCPropertyImplDecl::Dynamic),
- Ivar, PropertyIvarLoc);
- if (CompleteTypeErr || !compat)
- PIDecl->setInvalidDecl();
- if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
- getterMethod->createImplicitParams(Context, IDecl);
- // Redeclare the getter within the implementation as DeclContext.
- if (Synthesize) {
- // If the method hasn't been overridden, create a synthesized implementation.
- ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
- getterMethod->getSelector(), getterMethod->isInstanceMethod());
- if (!OMD)
- OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,
- PropertyLoc);
- PIDecl->setGetterMethodDecl(OMD);
- }
- if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
- Ivar->getType()->isRecordType()) {
- // For Objective-C++, need to synthesize the AST for the IVAR object to be
- // returned by the getter as it must conform to C++'s copy-return rules.
- // FIXME. Eventually we want to do this for Objective-C as well.
- SynthesizedFunctionScope Scope(*this, getterMethod);
- ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
- DeclRefExpr *SelfExpr = new (Context)
- DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
- PropertyDiagLoc);
- MarkDeclRefReferenced(SelfExpr);
- Expr *LoadSelfExpr = ImplicitCastExpr::Create(
- Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
- VK_PRValue, FPOptionsOverride());
- Expr *IvarRefExpr =
- new (Context) ObjCIvarRefExpr(Ivar,
- Ivar->getUsageType(SelfDecl->getType()),
- PropertyDiagLoc,
- Ivar->getLocation(),
- LoadSelfExpr, true, true);
- ExprResult Res = PerformCopyInitialization(
- InitializedEntity::InitializeResult(PropertyDiagLoc,
- getterMethod->getReturnType()),
- PropertyDiagLoc, IvarRefExpr);
- if (!Res.isInvalid()) {
- Expr *ResExpr = Res.getAs<Expr>();
- if (ResExpr)
- ResExpr = MaybeCreateExprWithCleanups(ResExpr);
- PIDecl->setGetterCXXConstructor(ResExpr);
- }
- }
- if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
- !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
- Diag(getterMethod->getLocation(),
- diag::warn_property_getter_owning_mismatch);
- Diag(property->getLocation(), diag::note_property_declare);
- }
- if (getLangOpts().ObjCAutoRefCount && Synthesize)
- switch (getterMethod->getMethodFamily()) {
- case OMF_retain:
- case OMF_retainCount:
- case OMF_release:
- case OMF_autorelease:
- Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)
- << 1 << getterMethod->getSelector();
- break;
- default:
- break;
- }
- }
- if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
- setterMethod->createImplicitParams(Context, IDecl);
- // Redeclare the setter within the implementation as DeclContext.
- if (Synthesize) {
- ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
- setterMethod->getSelector(), setterMethod->isInstanceMethod());
- if (!OMD)
- OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,
- AtLoc, PropertyLoc);
- PIDecl->setSetterMethodDecl(OMD);
- }
- if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
- Ivar->getType()->isRecordType()) {
- // FIXME. Eventually we want to do this for Objective-C as well.
- SynthesizedFunctionScope Scope(*this, setterMethod);
- ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
- DeclRefExpr *SelfExpr = new (Context)
- DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
- PropertyDiagLoc);
- MarkDeclRefReferenced(SelfExpr);
- Expr *LoadSelfExpr = ImplicitCastExpr::Create(
- Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
- VK_PRValue, FPOptionsOverride());
- Expr *lhs =
- new (Context) ObjCIvarRefExpr(Ivar,
- Ivar->getUsageType(SelfDecl->getType()),
- PropertyDiagLoc,
- Ivar->getLocation(),
- LoadSelfExpr, true, true);
- ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
- ParmVarDecl *Param = (*P);
- QualType T = Param->getType().getNonReferenceType();
- DeclRefExpr *rhs = new (Context)
- DeclRefExpr(Context, Param, false, T, VK_LValue, PropertyDiagLoc);
- MarkDeclRefReferenced(rhs);
- ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
- BO_Assign, lhs, rhs);
- if (property->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_atomic) {
- Expr *callExpr = Res.getAs<Expr>();
- if (const CXXOperatorCallExpr *CXXCE =
- dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
- if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
- if (!FuncDecl->isTrivial())
- if (property->getType()->isReferenceType()) {
- Diag(PropertyDiagLoc,
- diag::err_atomic_property_nontrivial_assign_op)
- << property->getType();
- Diag(FuncDecl->getBeginLoc(), diag::note_callee_decl)
- << FuncDecl;
- }
- }
- PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());
- }
- }
- if (IC) {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- IC->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::err_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
- if (ObjCPropertyImplDecl *PPIDecl
- = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {
- Diag(PropertyLoc, diag::err_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return nullptr;
- }
- IC->addPropertyImplementation(PIDecl);
- if (getLangOpts().ObjCDefaultSynthProperties &&
- getLangOpts().ObjCRuntime.isNonFragile() &&
- !IDecl->isObjCRequiresPropertyDefs()) {
- // Diagnose if an ivar was lazily synthesdized due to a previous
- // use and if 1) property is @dynamic or 2) property is synthesized
- // but it requires an ivar of different name.
- ObjCInterfaceDecl *ClassDeclared=nullptr;
- ObjCIvarDecl *Ivar = nullptr;
- if (!Synthesize)
- Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
- else {
- if (PropertyIvar && PropertyIvar != PropertyId)
- Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
- }
- // Issue diagnostics only if Ivar belongs to current class.
- if (Ivar && Ivar->getSynthesize() &&
- declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {
- Diag(Ivar->getLocation(), diag::err_undeclared_var_use)
- << PropertyId;
- Ivar->setInvalidDecl();
- }
- }
- } else {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyDiagLoc, diag::err_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {
- Diag(PropertyDiagLoc, diag::err_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return nullptr;
- }
- CatImplClass->addPropertyImplementation(PIDecl);
- }
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic &&
- PIDecl->getPropertyDecl() &&
- PIDecl->getPropertyDecl()->isDirectProperty()) {
- Diag(PropertyLoc, diag::err_objc_direct_dynamic_property);
- Diag(PIDecl->getPropertyDecl()->getLocation(),
- diag::note_previous_declaration);
- return nullptr;
- }
- return PIDecl;
- }
- //===----------------------------------------------------------------------===//
- // Helper methods.
- //===----------------------------------------------------------------------===//
- /// DiagnosePropertyMismatch - Compares two properties for their
- /// attributes and types and warns on a variety of inconsistencies.
- ///
- void
- Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
- ObjCPropertyDecl *SuperProperty,
- const IdentifierInfo *inheritedName,
- bool OverridingProtocolProperty) {
- ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes();
- ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes();
- // We allow readonly properties without an explicit ownership
- // (assign/unsafe_unretained/weak/retain/strong/copy) in super class
- // to be overridden by a property with any explicit ownership in the subclass.
- if (!OverridingProtocolProperty &&
- !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
- ;
- else {
- if ((CAttr & ObjCPropertyAttribute::kind_readonly) &&
- (SAttr & ObjCPropertyAttribute::kind_readwrite))
- Diag(Property->getLocation(), diag::warn_readonly_property)
- << Property->getDeclName() << inheritedName;
- if ((CAttr & ObjCPropertyAttribute::kind_copy) !=
- (SAttr & ObjCPropertyAttribute::kind_copy))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "copy" << inheritedName;
- else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) {
- unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong));
- unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong));
- bool CStrong = (CAttrRetain != 0);
- bool SStrong = (SAttrRetain != 0);
- if (CStrong != SStrong)
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain (or strong)" << inheritedName;
- }
- }
- // Check for nonatomic; note that nonatomic is effectively
- // meaningless for readonly properties, so don't diagnose if the
- // atomic property is 'readonly'.
- checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
- // Readonly properties from protocols can be implemented as "readwrite"
- // with a custom setter name.
- if (Property->getSetterName() != SuperProperty->getSetterName() &&
- !(SuperProperty->isReadOnly() &&
- isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "setter" << inheritedName;
- Diag(SuperProperty->getLocation(), diag::note_property_declare);
- }
- if (Property->getGetterName() != SuperProperty->getGetterName()) {
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "getter" << inheritedName;
- Diag(SuperProperty->getLocation(), diag::note_property_declare);
- }
- QualType LHSType =
- Context.getCanonicalType(SuperProperty->getType());
- QualType RHSType =
- Context.getCanonicalType(Property->getType());
- if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
- // Do cases not handled in above.
- // FIXME. For future support of covariant property types, revisit this.
- bool IncompatibleObjC = false;
- QualType ConvertedType;
- if (!isObjCPointerConversion(RHSType, LHSType,
- ConvertedType, IncompatibleObjC) ||
- IncompatibleObjC) {
- Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
- << Property->getType() << SuperProperty->getType() << inheritedName;
- Diag(SuperProperty->getLocation(), diag::note_property_declare);
- }
- }
- }
- bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
- ObjCMethodDecl *GetterMethod,
- SourceLocation Loc) {
- if (!GetterMethod)
- return false;
- QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
- QualType PropertyRValueType =
- property->getType().getNonReferenceType().getAtomicUnqualifiedType();
- bool compat = Context.hasSameType(PropertyRValueType, GetterType);
- if (!compat) {
- const ObjCObjectPointerType *propertyObjCPtr = nullptr;
- const ObjCObjectPointerType *getterObjCPtr = nullptr;
- if ((propertyObjCPtr =
- PropertyRValueType->getAs<ObjCObjectPointerType>()) &&
- (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
- compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
- else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType)
- != Compatible) {
- Diag(Loc, diag::err_property_accessor_type)
- << property->getDeclName() << PropertyRValueType
- << GetterMethod->getSelector() << GetterType;
- Diag(GetterMethod->getLocation(), diag::note_declared_at);
- return true;
- } else {
- compat = true;
- QualType lhsType = Context.getCanonicalType(PropertyRValueType);
- QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
- if (lhsType != rhsType && lhsType->isArithmeticType())
- compat = false;
- }
- }
- if (!compat) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << GetterMethod->getSelector();
- Diag(GetterMethod->getLocation(), diag::note_declared_at);
- return true;
- }
- return false;
- }
- /// CollectImmediateProperties - This routine collects all properties in
- /// the class and its conforming protocols; but not those in its super class.
- static void
- CollectImmediateProperties(ObjCContainerDecl *CDecl,
- ObjCContainerDecl::PropertyMap &PropMap,
- ObjCContainerDecl::PropertyMap &SuperPropMap,
- bool CollectClassPropsOnly = false,
- bool IncludeProtocols = true) {
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (auto *Prop : IDecl->properties()) {
- if (CollectClassPropsOnly && !Prop->isClassProperty())
- continue;
- PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
- Prop;
- }
- // Collect the properties from visible extensions.
- for (auto *Ext : IDecl->visible_extensions())
- CollectImmediateProperties(Ext, PropMap, SuperPropMap,
- CollectClassPropsOnly, IncludeProtocols);
- if (IncludeProtocols) {
- // Scan through class's protocols.
- for (auto *PI : IDecl->all_referenced_protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap,
- CollectClassPropsOnly);
- }
- }
- if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (auto *Prop : CATDecl->properties()) {
- if (CollectClassPropsOnly && !Prop->isClassProperty())
- continue;
- PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
- Prop;
- }
- if (IncludeProtocols) {
- // Scan through class's protocols.
- for (auto *PI : CATDecl->protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap,
- CollectClassPropsOnly);
- }
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (auto *Prop : PDecl->properties()) {
- if (CollectClassPropsOnly && !Prop->isClassProperty())
- continue;
- ObjCPropertyDecl *PropertyFromSuper =
- SuperPropMap[std::make_pair(Prop->getIdentifier(),
- Prop->isClassProperty())];
- // Exclude property for protocols which conform to class's super-class,
- // as super-class has to implement the property.
- if (!PropertyFromSuper ||
- PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
- ObjCPropertyDecl *&PropEntry =
- PropMap[std::make_pair(Prop->getIdentifier(),
- Prop->isClassProperty())];
- if (!PropEntry)
- PropEntry = Prop;
- }
- }
- // Scan through protocol's protocols.
- for (auto *PI : PDecl->protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap,
- CollectClassPropsOnly);
- }
- }
- /// CollectSuperClassPropertyImplementations - This routine collects list of
- /// properties to be implemented in super class(s) and also coming from their
- /// conforming protocols.
- static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
- ObjCInterfaceDecl::PropertyMap &PropMap) {
- if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
- while (SDecl) {
- SDecl->collectPropertiesToImplement(PropMap);
- SDecl = SDecl->getSuperClass();
- }
- }
- }
- /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
- /// an ivar synthesized for 'Method' and 'Method' is a property accessor
- /// declared in class 'IFace'.
- bool
- Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
- ObjCMethodDecl *Method, ObjCIvarDecl *IV) {
- if (!IV->getSynthesize())
- return false;
- ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
- Method->isInstanceMethod());
- if (!IMD || !IMD->isPropertyAccessor())
- return false;
- // look up a property declaration whose one of its accessors is implemented
- // by this method.
- for (const auto *Property : IFace->instance_properties()) {
- if ((Property->getGetterName() == IMD->getSelector() ||
- Property->getSetterName() == IMD->getSelector()) &&
- (Property->getPropertyIvarDecl() == IV))
- return true;
- }
- // Also look up property declaration in class extension whose one of its
- // accessors is implemented by this method.
- for (const auto *Ext : IFace->known_extensions())
- for (const auto *Property : Ext->instance_properties())
- if ((Property->getGetterName() == IMD->getSelector() ||
- Property->getSetterName() == IMD->getSelector()) &&
- (Property->getPropertyIvarDecl() == IV))
- return true;
- return false;
- }
- static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
- ObjCPropertyDecl *Prop) {
- bool SuperClassImplementsGetter = false;
- bool SuperClassImplementsSetter = false;
- if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
- SuperClassImplementsSetter = true;
- while (IDecl->getSuperClass()) {
- ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
- if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))
- SuperClassImplementsGetter = true;
- if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))
- SuperClassImplementsSetter = true;
- if (SuperClassImplementsGetter && SuperClassImplementsSetter)
- return true;
- IDecl = IDecl->getSuperClass();
- }
- return false;
- }
- /// Default synthesizes all properties which must be synthesized
- /// in class's \@implementation.
- void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
- ObjCInterfaceDecl *IDecl,
- SourceLocation AtEnd) {
- ObjCInterfaceDecl::PropertyMap PropMap;
- IDecl->collectPropertiesToImplement(PropMap);
- if (PropMap.empty())
- return;
- ObjCInterfaceDecl::PropertyMap SuperPropMap;
- CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (const auto &PropEntry : PropMap) {
- ObjCPropertyDecl *Prop = PropEntry.second;
- // Is there a matching property synthesize/dynamic?
- if (Prop->isInvalidDecl() ||
- Prop->isClassProperty() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
- continue;
- // Property may have been synthesized by user.
- if (IMPDecl->FindPropertyImplDecl(
- Prop->getIdentifier(), Prop->getQueryKind()))
- continue;
- ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
- if (ImpMethod && !ImpMethod->getBody()) {
- if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
- continue;
- ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
- if (ImpMethod && !ImpMethod->getBody())
- continue;
- }
- if (ObjCPropertyImplDecl *PID =
- IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
- Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
- << Prop->getIdentifier();
- if (PID->getLocation().isValid())
- Diag(PID->getLocation(), diag::note_property_synthesize);
- continue;
- }
- ObjCPropertyDecl *PropInSuperClass =
- SuperPropMap[std::make_pair(Prop->getIdentifier(),
- Prop->isClassProperty())];
- if (ObjCProtocolDecl *Proto =
- dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
- // We won't auto-synthesize properties declared in protocols.
- // Suppress the warning if class's superclass implements property's
- // getter and implements property's setter (if readwrite property).
- // Or, if property is going to be implemented in its super class.
- if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {
- Diag(IMPDecl->getLocation(),
- diag::warn_auto_synthesizing_protocol_property)
- << Prop << Proto;
- Diag(Prop->getLocation(), diag::note_property_declare);
- std::string FixIt =
- (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();
- Diag(AtEnd, diag::note_add_synthesize_directive)
- << FixItHint::CreateInsertion(AtEnd, FixIt);
- }
- continue;
- }
- // If property to be implemented in the super class, ignore.
- if (PropInSuperClass) {
- if ((Prop->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_readwrite) &&
- (PropInSuperClass->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_readonly) &&
- !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
- !IDecl->HasUserDeclaredSetterMethod(Prop)) {
- Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
- << Prop->getIdentifier();
- Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
- } else {
- Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
- << Prop->getIdentifier();
- Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
- Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
- }
- continue;
- }
- // We use invalid SourceLocations for the synthesized ivars since they
- // aren't really synthesized at a particular location; they just exist.
- // Saying that they are located at the @implementation isn't really going
- // to help users.
- ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(
- ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
- true,
- /* property = */ Prop->getIdentifier(),
- /* ivar = */ Prop->getDefaultSynthIvarName(Context),
- Prop->getLocation(), Prop->getQueryKind()));
- if (PIDecl && !Prop->isUnavailable()) {
- Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
- Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
- }
- }
- }
- void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D,
- SourceLocation AtEnd) {
- if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
- return;
- ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
- if (!IC)
- return;
- if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
- if (!IDecl->isObjCRequiresPropertyDefs())
- DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);
- }
- static void DiagnoseUnimplementedAccessor(
- Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method,
- ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C,
- ObjCPropertyDecl *Prop,
- llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) {
- // Check to see if we have a corresponding selector in SMap and with the
- // right method type.
- auto I = llvm::find_if(SMap, [&](const ObjCMethodDecl *x) {
- return x->getSelector() == Method &&
- x->isClassMethod() == Prop->isClassProperty();
- });
- // When reporting on missing property setter/getter implementation in
- // categories, do not report when they are declared in primary class,
- // class's protocol, or one of it super classes. This is because,
- // the class is going to implement them.
- if (I == SMap.end() &&
- (PrimaryClass == nullptr ||
- !PrimaryClass->lookupPropertyAccessor(Method, C,
- Prop->isClassProperty()))) {
- unsigned diag =
- isa<ObjCCategoryDecl>(CDecl)
- ? (Prop->isClassProperty()
- ? diag::warn_impl_required_in_category_for_class_property
- : diag::warn_setter_getter_impl_required_in_category)
- : (Prop->isClassProperty()
- ? diag::warn_impl_required_for_class_property
- : diag::warn_setter_getter_impl_required);
- S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;
- S.Diag(Prop->getLocation(), diag::note_property_declare);
- if (S.LangOpts.ObjCDefaultSynthProperties &&
- S.LangOpts.ObjCRuntime.isNonFragile())
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
- S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
- }
- }
- void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
- ObjCContainerDecl *CDecl,
- bool SynthesizeProperties) {
- ObjCContainerDecl::PropertyMap PropMap;
- ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
- // Since we don't synthesize class properties, we should emit diagnose even
- // if SynthesizeProperties is true.
- ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
- // Gather properties which need not be implemented in this class
- // or category.
- if (!IDecl)
- if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- // For categories, no need to implement properties declared in
- // its primary class (and its super classes) if property is
- // declared in one of those containers.
- if ((IDecl = C->getClassInterface())) {
- IDecl->collectPropertiesToImplement(NoNeedToImplPropMap);
- }
- }
- if (IDecl)
- CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
- // When SynthesizeProperties is true, we only check class properties.
- CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,
- SynthesizeProperties/*CollectClassPropsOnly*/);
- // Scan the @interface to see if any of the protocols it adopts
- // require an explicit implementation, via attribute
- // 'objc_protocol_requires_explicit_implementation'.
- if (IDecl) {
- std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;
- for (auto *PDecl : IDecl->all_referenced_protocols()) {
- if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
- continue;
- // Lazily construct a set of all the properties in the @interface
- // of the class, without looking at the superclass. We cannot
- // use the call to CollectImmediateProperties() above as that
- // utilizes information from the super class's properties as well
- // as scans the adopted protocols. This work only triggers for protocols
- // with the attribute, which is very rare, and only occurs when
- // analyzing the @implementation.
- if (!LazyMap) {
- ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
- LazyMap.reset(new ObjCContainerDecl::PropertyMap());
- CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
- /* CollectClassPropsOnly */ false,
- /* IncludeProtocols */ false);
- }
- // Add the properties of 'PDecl' to the list of properties that
- // need to be implemented.
- for (auto *PropDecl : PDecl->properties()) {
- if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),
- PropDecl->isClassProperty())])
- continue;
- PropMap[std::make_pair(PropDecl->getIdentifier(),
- PropDecl->isClassProperty())] = PropDecl;
- }
- }
- }
- if (PropMap.empty())
- return;
- llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
- for (const auto *I : IMPDecl->property_impls())
- PropImplMap.insert(I->getPropertyDecl());
- llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap;
- // Collect property accessors implemented in current implementation.
- for (const auto *I : IMPDecl->methods())
- InsMap.insert(I);
- ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
- ObjCInterfaceDecl *PrimaryClass = nullptr;
- if (C && !C->IsClassExtension())
- if ((PrimaryClass = C->getClassInterface()))
- // Report unimplemented properties in the category as well.
- if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {
- // When reporting on missing setter/getters, do not report when
- // setter/getter is implemented in category's primary class
- // implementation.
- for (const auto *I : IMP->methods())
- InsMap.insert(I);
- }
- for (ObjCContainerDecl::PropertyMap::iterator
- P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = P->second;
- // Is there a matching property synthesize/dynamic?
- if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop) ||
- Prop->getAvailability() == AR_Unavailable)
- continue;
- // Diagnose unimplemented getters and setters.
- DiagnoseUnimplementedAccessor(*this,
- PrimaryClass, Prop->getGetterName(), IMPDecl, CDecl, C, Prop, InsMap);
- if (!Prop->isReadOnly())
- DiagnoseUnimplementedAccessor(*this,
- PrimaryClass, Prop->getSetterName(),
- IMPDecl, CDecl, C, Prop, InsMap);
- }
- }
- void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) {
- for (const auto *propertyImpl : impDecl->property_impls()) {
- const auto *property = propertyImpl->getPropertyDecl();
- // Warn about null_resettable properties with synthesized setters,
- // because the setter won't properly handle nil.
- if (propertyImpl->getPropertyImplementation() ==
- ObjCPropertyImplDecl::Synthesize &&
- (property->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_null_resettable) &&
- property->getGetterMethodDecl() && property->getSetterMethodDecl()) {
- auto *getterImpl = propertyImpl->getGetterMethodDecl();
- auto *setterImpl = propertyImpl->getSetterMethodDecl();
- if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
- (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
- SourceLocation loc = propertyImpl->getLocation();
- if (loc.isInvalid())
- loc = impDecl->getBeginLoc();
- Diag(loc, diag::warn_null_resettable_setter)
- << setterImpl->getSelector() << property->getDeclName();
- }
- }
- }
- }
- void
- Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl* IDecl) {
- // Rules apply in non-GC mode only
- if (getLangOpts().getGC() != LangOptions::NonGC)
- return;
- ObjCContainerDecl::PropertyMap PM;
- for (auto *Prop : IDecl->properties())
- PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- for (const auto *Ext : IDecl->known_extensions())
- for (auto *Prop : Ext->properties())
- PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
- I != E; ++I) {
- const ObjCPropertyDecl *Property = I->second;
- ObjCMethodDecl *GetterMethod = nullptr;
- ObjCMethodDecl *SetterMethod = nullptr;
- unsigned Attributes = Property->getPropertyAttributes();
- unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
- if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) &&
- !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) {
- GetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getGetterName()) :
- IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getSetterName()) :
- IMPDecl->getInstanceMethod(Property->getSetterName());
- if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
- GetterMethod = nullptr;
- if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
- SetterMethod = nullptr;
- if (GetterMethod) {
- Diag(GetterMethod->getLocation(),
- diag::warn_default_atomic_custom_getter_setter)
- << Property->getIdentifier() << 0;
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- if (SetterMethod) {
- Diag(SetterMethod->getLocation(),
- diag::warn_default_atomic_custom_getter_setter)
- << Property->getIdentifier() << 1;
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- }
- // We only care about readwrite atomic property.
- if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) ||
- !(Attributes & ObjCPropertyAttribute::kind_readwrite))
- continue;
- if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
- Property->getIdentifier(), Property->getQueryKind())) {
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- GetterMethod = PIDecl->getGetterMethodDecl();
- SetterMethod = PIDecl->getSetterMethodDecl();
- if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
- GetterMethod = nullptr;
- if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
- SetterMethod = nullptr;
- if ((bool)GetterMethod ^ (bool)SetterMethod) {
- SourceLocation MethodLoc =
- (GetterMethod ? GetterMethod->getLocation()
- : SetterMethod->getLocation());
- Diag(MethodLoc, diag::warn_atomic_property_rule)
- << Property->getIdentifier() << (GetterMethod != nullptr)
- << (SetterMethod != nullptr);
- // fixit stuff.
- if (Property->getLParenLoc().isValid() &&
- !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) {
- // @property () ... case.
- SourceLocation AfterLParen =
- getLocForEndOfToken(Property->getLParenLoc());
- StringRef NonatomicStr = AttributesAsWritten? "nonatomic, "
- : "nonatomic";
- Diag(Property->getLocation(),
- diag::note_atomic_property_fixup_suggest)
- << FixItHint::CreateInsertion(AfterLParen, NonatomicStr);
- } else if (Property->getLParenLoc().isInvalid()) {
- //@property id etc.
- SourceLocation startLoc =
- Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
- Diag(Property->getLocation(),
- diag::note_atomic_property_fixup_suggest)
- << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
- } else
- Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- }
- }
- }
- void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
- if (getLangOpts().getGC() == LangOptions::GCOnly)
- return;
- for (const auto *PID : D->property_impls()) {
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
- !PD->isClassProperty()) {
- ObjCMethodDecl *IM = PID->getGetterMethodDecl();
- if (IM && !IM->isSynthesizedAccessorStub())
- continue;
- ObjCMethodDecl *method = PD->getGetterMethodDecl();
- if (!method)
- continue;
- ObjCMethodFamily family = method->getMethodFamily();
- if (family == OMF_alloc || family == OMF_copy ||
- family == OMF_mutableCopy || family == OMF_new) {
- if (getLangOpts().ObjCAutoRefCount)
- Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);
- else
- Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);
- // Look for a getter explicitly declared alongside the property.
- // If we find one, use its location for the note.
- SourceLocation noteLoc = PD->getLocation();
- SourceLocation fixItLoc;
- for (auto *getterRedecl : method->redecls()) {
- if (getterRedecl->isImplicit())
- continue;
- if (getterRedecl->getDeclContext() != PD->getDeclContext())
- continue;
- noteLoc = getterRedecl->getLocation();
- fixItLoc = getterRedecl->getEndLoc();
- }
- Preprocessor &PP = getPreprocessor();
- TokenValue tokens[] = {
- tok::kw___attribute, tok::l_paren, tok::l_paren,
- PP.getIdentifierInfo("objc_method_family"), tok::l_paren,
- PP.getIdentifierInfo("none"), tok::r_paren,
- tok::r_paren, tok::r_paren
- };
- StringRef spelling = "__attribute__((objc_method_family(none)))";
- StringRef macroName = PP.getLastMacroWithSpelling(noteLoc, tokens);
- if (!macroName.empty())
- spelling = macroName;
- auto noteDiag = Diag(noteLoc, diag::note_cocoa_naming_declare_family)
- << method->getDeclName() << spelling;
- if (fixItLoc.isValid()) {
- SmallString<64> fixItText(" ");
- fixItText += spelling;
- noteDiag << FixItHint::CreateInsertion(fixItLoc, fixItText);
- }
- }
- }
- }
- }
- void Sema::DiagnoseMissingDesignatedInitOverrides(
- const ObjCImplementationDecl *ImplD,
- const ObjCInterfaceDecl *IFD) {
- assert(IFD->hasDesignatedInitializers());
- const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();
- if (!SuperD)
- return;
- SelectorSet InitSelSet;
- for (const auto *I : ImplD->instance_methods())
- if (I->getMethodFamily() == OMF_init)
- InitSelSet.insert(I->getSelector());
- SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;
- SuperD->getDesignatedInitializers(DesignatedInits);
- for (SmallVector<const ObjCMethodDecl *, 8>::iterator
- I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
- const ObjCMethodDecl *MD = *I;
- if (!InitSelSet.count(MD->getSelector())) {
- // Don't emit a diagnostic if the overriding method in the subclass is
- // marked as unavailable.
- bool Ignore = false;
- if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) {
- Ignore = IMD->isUnavailable();
- } else {
- // Check the methods declared in the class extensions too.
- for (auto *Ext : IFD->visible_extensions())
- if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) {
- Ignore = IMD->isUnavailable();
- break;
- }
- }
- if (!Ignore) {
- Diag(ImplD->getLocation(),
- diag::warn_objc_implementation_missing_designated_init_override)
- << MD->getSelector();
- Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);
- }
- }
- }
- }
- /// AddPropertyAttrs - Propagates attributes from a property to the
- /// implicitly-declared getter or setter for that property.
- static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
- ObjCPropertyDecl *Property) {
- // Should we just clone all attributes over?
- for (const auto *A : Property->attrs()) {
- if (isa<DeprecatedAttr>(A) ||
- isa<UnavailableAttr>(A) ||
- isa<AvailabilityAttr>(A))
- PropertyMethod->addAttr(A->clone(S.Context));
- }
- }
- /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
- /// have the property type and issue diagnostics if they don't.
- /// Also synthesize a getter/setter method if none exist (and update the
- /// appropriate lookup tables.
- void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
- ObjCMethodDecl *GetterMethod, *SetterMethod;
- ObjCContainerDecl *CD = cast<ObjCContainerDecl>(property->getDeclContext());
- if (CD->isInvalidDecl())
- return;
- bool IsClassProperty = property->isClassProperty();
- GetterMethod = IsClassProperty ?
- CD->getClassMethod(property->getGetterName()) :
- CD->getInstanceMethod(property->getGetterName());
- // if setter or getter is not found in class extension, it might be
- // in the primary class.
- if (!GetterMethod)
- if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
- if (CatDecl->IsClassExtension())
- GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
- getClassMethod(property->getGetterName()) :
- CatDecl->getClassInterface()->
- getInstanceMethod(property->getGetterName());
- SetterMethod = IsClassProperty ?
- CD->getClassMethod(property->getSetterName()) :
- CD->getInstanceMethod(property->getSetterName());
- if (!SetterMethod)
- if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
- if (CatDecl->IsClassExtension())
- SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
- getClassMethod(property->getSetterName()) :
- CatDecl->getClassInterface()->
- getInstanceMethod(property->getSetterName());
- DiagnosePropertyAccessorMismatch(property, GetterMethod,
- property->getLocation());
- // synthesizing accessors must not result in a direct method that is not
- // monomorphic
- if (!GetterMethod) {
- if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
- auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(
- property->getGetterName(), !IsClassProperty, true, false, CatDecl);
- if (ExistingGetter) {
- if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {
- Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
- << property->isDirectProperty() << 1 /* property */
- << ExistingGetter->isDirectMethod()
- << ExistingGetter->getDeclName();
- Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);
- }
- }
- }
- }
- if (!property->isReadOnly() && !SetterMethod) {
- if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
- auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(
- property->getSetterName(), !IsClassProperty, true, false, CatDecl);
- if (ExistingSetter) {
- if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {
- Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
- << property->isDirectProperty() << 1 /* property */
- << ExistingSetter->isDirectMethod()
- << ExistingSetter->getDeclName();
- Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);
- }
- }
- }
- }
- if (!property->isReadOnly() && SetterMethod) {
- if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
- Context.VoidTy)
- Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
- if (SetterMethod->param_size() != 1 ||
- !Context.hasSameUnqualifiedType(
- (*SetterMethod->param_begin())->getType().getNonReferenceType(),
- property->getType().getNonReferenceType())) {
- Diag(property->getLocation(),
- diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << SetterMethod->getSelector();
- Diag(SetterMethod->getLocation(), diag::note_declared_at);
- }
- }
- // Synthesize getter/setter methods if none exist.
- // Find the default getter and if one not found, add one.
- // FIXME: The synthesized property we set here is misleading. We almost always
- // synthesize these methods unless the user explicitly provided prototypes
- // (which is odd, but allowed). Sema should be typechecking that the
- // declarations jive in that situation (which it is not currently).
- if (!GetterMethod) {
- // No instance/class method of same name as property getter name was found.
- // Declare a getter method and add it to the list of methods
- // for this class.
- SourceLocation Loc = property->getLocation();
- // The getter returns the declared property type with all qualifiers
- // removed.
- QualType resultTy = property->getType().getAtomicUnqualifiedType();
- // If the property is null_resettable, the getter returns nonnull.
- if (property->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_null_resettable) {
- QualType modifiedTy = resultTy;
- if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
- if (*nullability == NullabilityKind::Unspecified)
- resultTy = Context.getAttributedType(attr::TypeNonNull,
- modifiedTy, modifiedTy);
- }
- }
- GetterMethod = ObjCMethodDecl::Create(
- Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
- !IsClassProperty, /*isVariadic=*/false,
- /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
- ? ObjCMethodDecl::Optional
- : ObjCMethodDecl::Required);
- CD->addDecl(GetterMethod);
- AddPropertyAttrs(*this, GetterMethod, property);
- if (property->isDirectProperty())
- GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
- if (property->hasAttr<NSReturnsNotRetainedAttr>())
- GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
- Loc));
- if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
- GetterMethod->addAttr(
- ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
- if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- GetterMethod->addAttr(SectionAttr::CreateImplicit(
- Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
- SectionAttr::GNU_section));
- if (getLangOpts().ObjCAutoRefCount)
- CheckARCMethodDecl(GetterMethod);
- } else
- // A user declared getter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- GetterMethod->setPropertyAccessor(true);
- GetterMethod->createImplicitParams(Context,
- GetterMethod->getClassInterface());
- property->setGetterMethodDecl(GetterMethod);
- // Skip setter if property is read-only.
- if (!property->isReadOnly()) {
- // Find the default setter and if one not found, add one.
- if (!SetterMethod) {
- // No instance/class method of same name as property setter name was
- // found.
- // Declare a setter method and add it to the list of methods
- // for this class.
- SourceLocation Loc = property->getLocation();
- SetterMethod =
- ObjCMethodDecl::Create(Context, Loc, Loc,
- property->getSetterName(), Context.VoidTy,
- nullptr, CD, !IsClassProperty,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/true,
- /*isSynthesizedAccessorStub=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
- // Remove all qualifiers from the setter's parameter type.
- QualType paramTy =
- property->getType().getUnqualifiedType().getAtomicUnqualifiedType();
- // If the property is null_resettable, the setter accepts a
- // nullable value.
- if (property->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_null_resettable) {
- QualType modifiedTy = paramTy;
- if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
- if (*nullability == NullabilityKind::Unspecified)
- paramTy = Context.getAttributedType(attr::TypeNullable,
- modifiedTy, modifiedTy);
- }
- }
- // Invent the arguments for the setter. We don't bother making a
- // nice name for the argument.
- ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
- Loc, Loc,
- property->getIdentifier(),
- paramTy,
- /*TInfo=*/nullptr,
- SC_None,
- nullptr);
- SetterMethod->setMethodParams(Context, Argument, std::nullopt);
- AddPropertyAttrs(*this, SetterMethod, property);
- if (property->isDirectProperty())
- SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
- CD->addDecl(SetterMethod);
- if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- SetterMethod->addAttr(SectionAttr::CreateImplicit(
- Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
- SectionAttr::GNU_section));
- // It's possible for the user to have set a very odd custom
- // setter selector that causes it to have a method family.
- if (getLangOpts().ObjCAutoRefCount)
- CheckARCMethodDecl(SetterMethod);
- } else
- // A user declared setter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- SetterMethod->setPropertyAccessor(true);
- SetterMethod->createImplicitParams(Context,
- SetterMethod->getClassInterface());
- property->setSetterMethodDecl(SetterMethod);
- }
- // Add any synthesized methods to the global pool. This allows us to
- // handle the following, which is supported by GCC (and part of the design).
- //
- // @interface Foo
- // @property double bar;
- // @end
- //
- // void thisIsUnfortunate() {
- // id foo;
- // double bar = [foo bar];
- // }
- //
- if (!IsClassProperty) {
- if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
- } else {
- if (GetterMethod)
- AddFactoryMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddFactoryMethodToGlobalPool(SetterMethod);
- }
- ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
- if (!CurrentClass) {
- if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))
- CurrentClass = Cat->getClassInterface();
- else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))
- CurrentClass = Impl->getClassInterface();
- }
- if (GetterMethod)
- CheckObjCMethodOverrides(GetterMethod, CurrentClass, Sema::RTC_Unknown);
- if (SetterMethod)
- CheckObjCMethodOverrides(SetterMethod, CurrentClass, Sema::RTC_Unknown);
- }
- void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
- SourceLocation Loc,
- unsigned &Attributes,
- bool propertyInPrimaryClass) {
- // FIXME: Improve the reported location.
- if (!PDecl || PDecl->isInvalidDecl())
- return;
- if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
- (Attributes & ObjCPropertyAttribute::kind_readwrite))
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "readonly" << "readwrite";
- ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
- QualType PropertyTy = PropertyDecl->getType();
- // Check for copy or retain on non-object types.
- if ((Attributes &
- (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
- ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong)) &&
- !PropertyTy->isObjCRetainableType() &&
- !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
- Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCPropertyAttribute::kind_weak
- ? "weak"
- : Attributes & ObjCPropertyAttribute::kind_copy
- ? "copy"
- : "retain (or strong)");
- Attributes &=
- ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
- ObjCPropertyAttribute::kind_retain |
- ObjCPropertyAttribute::kind_strong);
- PropertyDecl->setInvalidDecl();
- }
- // Check for assign on object types.
- if ((Attributes & ObjCPropertyAttribute::kind_assign) &&
- !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) &&
- PropertyTy->isObjCRetainableType() &&
- !PropertyTy->isObjCARCImplicitlyUnretainedType()) {
- Diag(Loc, diag::warn_objc_property_assign_on_object);
- }
- // Check for more than one of { assign, copy, retain }.
- if (Attributes & ObjCPropertyAttribute::kind_assign) {
- if (Attributes & ObjCPropertyAttribute::kind_copy) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "copy";
- Attributes &= ~ObjCPropertyAttribute::kind_copy;
- }
- if (Attributes & ObjCPropertyAttribute::kind_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "retain";
- Attributes &= ~ObjCPropertyAttribute::kind_retain;
- }
- if (Attributes & ObjCPropertyAttribute::kind_strong) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "strong";
- Attributes &= ~ObjCPropertyAttribute::kind_strong;
- }
- if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCPropertyAttribute::kind_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "weak";
- Attributes &= ~ObjCPropertyAttribute::kind_weak;
- }
- if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
- Diag(Loc, diag::warn_iboutletcollection_property_assign);
- } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) {
- if (Attributes & ObjCPropertyAttribute::kind_copy) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "unsafe_unretained" << "copy";
- Attributes &= ~ObjCPropertyAttribute::kind_copy;
- }
- if (Attributes & ObjCPropertyAttribute::kind_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "unsafe_unretained" << "retain";
- Attributes &= ~ObjCPropertyAttribute::kind_retain;
- }
- if (Attributes & ObjCPropertyAttribute::kind_strong) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "unsafe_unretained" << "strong";
- Attributes &= ~ObjCPropertyAttribute::kind_strong;
- }
- if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCPropertyAttribute::kind_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "unsafe_unretained" << "weak";
- Attributes &= ~ObjCPropertyAttribute::kind_weak;
- }
- } else if (Attributes & ObjCPropertyAttribute::kind_copy) {
- if (Attributes & ObjCPropertyAttribute::kind_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "copy" << "retain";
- Attributes &= ~ObjCPropertyAttribute::kind_retain;
- }
- if (Attributes & ObjCPropertyAttribute::kind_strong) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "copy" << "strong";
- Attributes &= ~ObjCPropertyAttribute::kind_strong;
- }
- if (Attributes & ObjCPropertyAttribute::kind_weak) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "copy" << "weak";
- Attributes &= ~ObjCPropertyAttribute::kind_weak;
- }
- } else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
- (Attributes & ObjCPropertyAttribute::kind_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain"
- << "weak";
- Attributes &= ~ObjCPropertyAttribute::kind_retain;
- } else if ((Attributes & ObjCPropertyAttribute::kind_strong) &&
- (Attributes & ObjCPropertyAttribute::kind_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong"
- << "weak";
- Attributes &= ~ObjCPropertyAttribute::kind_weak;
- }
- if (Attributes & ObjCPropertyAttribute::kind_weak) {
- // 'weak' and 'nonnull' are mutually exclusive.
- if (auto nullability = PropertyTy->getNullability()) {
- if (*nullability == NullabilityKind::NonNull)
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "nonnull" << "weak";
- }
- }
- if ((Attributes & ObjCPropertyAttribute::kind_atomic) &&
- (Attributes & ObjCPropertyAttribute::kind_nonatomic)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic"
- << "nonatomic";
- Attributes &= ~ObjCPropertyAttribute::kind_atomic;
- }
- // Warn if user supplied no assignment attribute, property is
- // readwrite, and this is an object type.
- if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) {
- if (Attributes & ObjCPropertyAttribute::kind_readonly) {
- // do nothing
- } else if (getLangOpts().ObjCAutoRefCount) {
- // With arc, @property definitions should default to strong when
- // not specified.
- PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
- } else if (PropertyTy->isObjCObjectPointerType()) {
- bool isAnyClassTy = (PropertyTy->isObjCClassType() ||
- PropertyTy->isObjCQualifiedClassType());
- // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
- // issue any warning.
- if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
- ;
- else if (propertyInPrimaryClass) {
- // Don't issue warning on property with no life time in class
- // extension as it is inherited from property in primary class.
- // Skip this warning in gc-only mode.
- if (getLangOpts().getGC() != LangOptions::GCOnly)
- Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
- // If non-gc code warn that this is likely inappropriate.
- if (getLangOpts().getGC() == LangOptions::NonGC)
- Diag(Loc, diag::warn_objc_property_default_assign_on_object);
- }
- }
- // FIXME: Implement warning dependent on NSCopying being
- // implemented. See also:
- // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
- // (please trim this list while you are at it).
- }
- if (!(Attributes & ObjCPropertyAttribute::kind_copy) &&
- !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
- getLangOpts().getGC() == LangOptions::GCOnly &&
- PropertyTy->isBlockPointerType())
- Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
- else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
- !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
- !(Attributes & ObjCPropertyAttribute::kind_strong) &&
- PropertyTy->isBlockPointerType())
- Diag(Loc, diag::warn_objc_property_retain_of_block);
- if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
- (Attributes & ObjCPropertyAttribute::kind_setter))
- Diag(Loc, diag::warn_objc_readonly_property_has_setter);
- }
|