void SynthesizeRemovalConsumer::removeSynthesizeDirectives(DeclContext *DC) { for(auto I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { // encounters @implementatian if (auto D = dyn_cast<ObjCImplDecl>(*I)) { // iterate through all the @synthesize / @dynamic directives for (auto PI = D->propimpl_begin(), PE = D->propimpl_end(); PI != PE; ++PI) { auto P = *PI; auto SR = P->getSourceRange(); // ignore if it's already an automatic @synthesize if (SR.getBegin().isInvalid()) { continue; } // ignore @dynamic if (P->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) { continue; } // if the ivar is not declared in the place where @synthesize is // (i.e. it is backed by some real ivar declared in @interface), // don't remove it auto PID = P->getPropertyIvarDecl(); if (P->getPropertyIvarDeclLoc() != PID->getLocation()) { continue; } // get the context in which the @property resides auto PD = P->getPropertyDecl(); auto PDC = PD->getDeclContext(); auto ID = dyn_cast<ObjCInterfaceDecl>(PDC); if (!ID) { continue; } // see if it's an @interface definition; this is false for @protocol // and we can only remove the synthesize decl for properties // declared within an @interface and not in @protocol if (!ID->isThisDeclarationADefinition()) { continue; } // check if the interface has the attribute // __attribute__((objc_requires_property_definitions)); if yes, the // directive cannot be removed bool attrObjCRequiresPropertyDefs = false; for (auto AI = ID->attr_begin(), AE = ID->attr_end(); AI != AE; ++AI) { if ((*AI)->getKind() == attr::ObjCRequiresPropertyDefs) { attrObjCRequiresPropertyDefs = true; break; } } if (attrObjCRequiresPropertyDefs) { continue; } // if there is both a manual getter *and* setter, it's equivalent to // a @dynamic, so we have to skip it auto GD = D->getInstanceMethod(PD->getGetterName()); auto SD = D->getInstanceMethod(PD->getSetterName()); if (GD && SD) { continue; } // another case for read-only properties if (GD && PD->isReadOnly()) { continue; } // scan past the ; token, get the end location SourceLocation EL = Lexer::findLocationAfterToken(SR.getEnd(), tok::semi, astContext->getSourceManager(), astContext->getLangOpts(), false); // probably run into a comma (compound directive) if (EL.isInvalid()) { continue; } // if it's a sub-directive after the comma, scan from the // beginning of the @synthesize token bool isCompoundDirective = false; const char *BCD = astContext->getSourceManager() .getCharacterData(SR.getBegin()); const char *ECD = astContext->getSourceManager() .getCharacterData(EL); while (BCD != ECD) { if (*BCD == ',') { isCompoundDirective = true; break; } ++BCD; } if (isCompoundDirective) { continue; } // check if the synthesized ivar name is not the same // as the property's name plus underscore std::string PIDN = PID->getNameAsString(); std::string PDN = PD->getNameAsString(); // handle the case where it's not @synthesize x = _x; std::string underscored = std::string("_") + PDN; if (PIDN != PDN) { if (PIDN != underscored) { continue; } } // see if the property is actually an ivar name of // some parent class! auto IF = preprocessor->getIdentifierInfo(underscored); if (IF) { auto IVDL = ID->lookupInstanceVariable(IF); if (IVDL && IVDL->getContainingInterface() != ID) { continue; } } // if parent class also have a property of the same name, // but of a different type, we can't remove it bool isOverridingProperty = false; auto S = ID->getSuperClass(); while (S) { auto SP = S->FindPropertyVisibleInPrimaryClass( PD->getIdentifier()); if (SP && (SP != PD)) { isOverridingProperty = true; break; } S = S->getSuperClass(); } if (isOverridingProperty) { continue; } // do the removal: record the removed directive removeSet.insert(P); // we want to remove the entire line if it becomes empty Rewriter::RewriteOptions RO; RO.RemoveLineIfEmpty = true; // and remove the @synthesize SourceRange RSR(SR.getBegin(), EL); rewriter.RemoveText(RSR, RO); } // PI } // D // descend into the next level (namespace, etc.) if (auto innerDC = dyn_cast<DeclContext>(*I)) { removeSynthesizeDirectives(innerDC); } } // DC }