1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266 |
- //===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- #include "Transforms.h"
- #include "clang/Analysis/RetainSummaryManager.h"
- #include "clang/ARCMigrate/ARCMT.h"
- #include "clang/ARCMigrate/ARCMTActions.h"
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Attr.h"
- #include "clang/AST/NSAPI.h"
- #include "clang/AST/ParentMap.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
- #include "clang/Basic/FileManager.h"
- #include "clang/Edit/Commit.h"
- #include "clang/Edit/EditedSource.h"
- #include "clang/Edit/EditsReceiver.h"
- #include "clang/Edit/Rewriters.h"
- #include "clang/Frontend/CompilerInstance.h"
- #include "clang/Frontend/MultiplexConsumer.h"
- #include "clang/Lex/PPConditionalDirectiveRecord.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Rewrite/Core/Rewriter.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/StringSet.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/SourceMgr.h"
- #include "llvm/Support/YAMLParser.h"
- using namespace clang;
- using namespace arcmt;
- using namespace ento;
- namespace {
- class ObjCMigrateASTConsumer : public ASTConsumer {
- enum CF_BRIDGING_KIND {
- CF_BRIDGING_NONE,
- CF_BRIDGING_ENABLE,
- CF_BRIDGING_MAY_INCLUDE
- };
- void migrateDecl(Decl *D);
- void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D);
- void migrateProtocolConformance(ASTContext &Ctx,
- const ObjCImplementationDecl *ImpDecl);
- void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
- bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
- const TypedefDecl *TypedefDcl);
- void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
- void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
- ObjCMethodDecl *OM);
- bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
- void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
- void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
- void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
- ObjCMethodDecl *OM,
- ObjCInstanceTypeFamily OIT_Family = OIT_None);
- void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
- void AddCFAnnotations(ASTContext &Ctx,
- const RetainSummary *RS,
- const FunctionDecl *FuncDecl, bool ResultAnnotated);
- void AddCFAnnotations(ASTContext &Ctx,
- const RetainSummary *RS,
- const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
- void AnnotateImplicitBridging(ASTContext &Ctx);
- CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
- const FunctionDecl *FuncDecl);
- void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
- void migrateAddMethodAnnotation(ASTContext &Ctx,
- const ObjCMethodDecl *MethodDecl);
- void inferDesignatedInitializers(ASTContext &Ctx,
- const ObjCImplementationDecl *ImplD);
- bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
- std::unique_ptr<RetainSummaryManager> Summaries;
- public:
- std::string MigrateDir;
- unsigned ASTMigrateActions;
- FileID FileId;
- const TypedefDecl *NSIntegerTypedefed;
- const TypedefDecl *NSUIntegerTypedefed;
- std::unique_ptr<NSAPI> NSAPIObj;
- std::unique_ptr<edit::EditedSource> Editor;
- FileRemapper &Remapper;
- FileManager &FileMgr;
- const PPConditionalDirectiveRecord *PPRec;
- Preprocessor &PP;
- bool IsOutputFile;
- bool FoundationIncluded;
- llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
- llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
- llvm::StringSet<> AllowListFilenames;
- RetainSummaryManager &getSummaryManager(ASTContext &Ctx) {
- if (!Summaries)
- Summaries.reset(new RetainSummaryManager(Ctx,
- /*TrackNSCFObjects=*/true,
- /*trackOSObjects=*/false));
- return *Summaries;
- }
- ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions,
- FileRemapper &remapper, FileManager &fileMgr,
- const PPConditionalDirectiveRecord *PPRec,
- Preprocessor &PP, bool isOutputFile,
- ArrayRef<std::string> AllowList)
- : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions),
- NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
- Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
- IsOutputFile(isOutputFile), FoundationIncluded(false) {
- // FIXME: StringSet should have insert(iter, iter) to use here.
- for (const std::string &Val : AllowList)
- AllowListFilenames.insert(Val);
- }
- protected:
- void Initialize(ASTContext &Context) override {
- NSAPIObj.reset(new NSAPI(Context));
- Editor.reset(new edit::EditedSource(Context.getSourceManager(),
- Context.getLangOpts(),
- PPRec));
- }
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
- for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
- migrateDecl(*I);
- return true;
- }
- void HandleInterestingDecl(DeclGroupRef DG) override {
- // Ignore decls from the PCH.
- }
- void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
- ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
- }
- void HandleTranslationUnit(ASTContext &Ctx) override;
- bool canModifyFile(StringRef Path) {
- if (AllowListFilenames.empty())
- return true;
- return AllowListFilenames.find(llvm::sys::path::filename(Path)) !=
- AllowListFilenames.end();
- }
- bool canModifyFile(Optional<FileEntryRef> FE) {
- if (!FE)
- return false;
- return canModifyFile(FE->getName());
- }
- bool canModifyFile(FileID FID) {
- if (FID.isInvalid())
- return false;
- return canModifyFile(PP.getSourceManager().getFileEntryRefForID(FID));
- }
- bool canModify(const Decl *D) {
- if (!D)
- return false;
- if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D))
- return canModify(CatImpl->getCategoryDecl());
- if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D))
- return canModify(Impl->getClassInterface());
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
- return canModify(cast<Decl>(MD->getDeclContext()));
- FileID FID = PP.getSourceManager().getFileID(D->getLocation());
- return canModifyFile(FID);
- }
- };
- } // end anonymous namespace
- ObjCMigrateAction::ObjCMigrateAction(
- std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
- unsigned migrateAction)
- : WrapperFrontendAction(std::move(WrappedAction)), MigrateDir(migrateDir),
- ObjCMigAction(migrateAction), CompInst(nullptr) {
- if (MigrateDir.empty())
- MigrateDir = "."; // user current directory if none is given.
- }
- std::unique_ptr<ASTConsumer>
- ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- PPConditionalDirectiveRecord *
- PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
- CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
- std::vector<std::unique_ptr<ASTConsumer>> Consumers;
- Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
- Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
- MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
- CompInst->getPreprocessor(), false, None));
- return std::make_unique<MultiplexConsumer>(std::move(Consumers));
- }
- bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
- Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
- /*ignoreIfFilesChanged=*/true);
- CompInst = &CI;
- CI.getDiagnostics().setIgnoreAllWarnings(true);
- return true;
- }
- namespace {
- // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
- bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
- const Expr* Expr = FullExpr->IgnoreImpCasts();
- return !(isa<ArraySubscriptExpr>(Expr) || isa<CallExpr>(Expr) ||
- isa<DeclRefExpr>(Expr) || isa<CXXNamedCastExpr>(Expr) ||
- isa<CXXConstructExpr>(Expr) || isa<CXXThisExpr>(Expr) ||
- isa<CXXTypeidExpr>(Expr) ||
- isa<CXXUnresolvedConstructExpr>(Expr) ||
- isa<ObjCMessageExpr>(Expr) || isa<ObjCPropertyRefExpr>(Expr) ||
- isa<ObjCProtocolExpr>(Expr) || isa<MemberExpr>(Expr) ||
- isa<ObjCIvarRefExpr>(Expr) || isa<ParenExpr>(FullExpr) ||
- isa<ParenListExpr>(Expr) || isa<SizeOfPackExpr>(Expr));
- }
- /// - Rewrite message expression for Objective-C setter and getters into
- /// property-dot syntax.
- bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
- Preprocessor &PP,
- const NSAPI &NS, edit::Commit &commit,
- const ParentMap *PMap) {
- if (!Msg || Msg->isImplicit() ||
- (Msg->getReceiverKind() != ObjCMessageExpr::Instance &&
- Msg->getReceiverKind() != ObjCMessageExpr::SuperInstance))
- return false;
- if (const Expr *Receiver = Msg->getInstanceReceiver())
- if (Receiver->getType()->isObjCBuiltinType())
- return false;
- const ObjCMethodDecl *Method = Msg->getMethodDecl();
- if (!Method)
- return false;
- if (!Method->isPropertyAccessor())
- return false;
- const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
- if (!Prop)
- return false;
- SourceRange MsgRange = Msg->getSourceRange();
- bool ReceiverIsSuper =
- (Msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
- // for 'super' receiver is nullptr.
- const Expr *receiver = Msg->getInstanceReceiver();
- bool NeedsParen =
- ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver);
- bool IsGetter = (Msg->getNumArgs() == 0);
- if (IsGetter) {
- // Find space location range between receiver expression and getter method.
- SourceLocation BegLoc =
- ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
- BegLoc = PP.getLocForEndOfToken(BegLoc);
- SourceLocation EndLoc = Msg->getSelectorLoc(0);
- SourceRange SpaceRange(BegLoc, EndLoc);
- std::string PropertyDotString;
- // rewrite getter method expression into: receiver.property or
- // (receiver).property
- if (NeedsParen) {
- commit.insertBefore(receiver->getBeginLoc(), "(");
- PropertyDotString = ").";
- }
- else
- PropertyDotString = ".";
- PropertyDotString += Prop->getName();
- commit.replace(SpaceRange, PropertyDotString);
- // remove '[' ']'
- commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
- commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
- } else {
- if (NeedsParen)
- commit.insertWrap("(", receiver->getSourceRange(), ")");
- std::string PropertyDotString = ".";
- PropertyDotString += Prop->getName();
- PropertyDotString += " =";
- const Expr*const* Args = Msg->getArgs();
- const Expr *RHS = Args[0];
- if (!RHS)
- return false;
- SourceLocation BegLoc =
- ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
- BegLoc = PP.getLocForEndOfToken(BegLoc);
- SourceLocation EndLoc = RHS->getBeginLoc();
- EndLoc = EndLoc.getLocWithOffset(-1);
- const char *colon = PP.getSourceManager().getCharacterData(EndLoc);
- // Add a space after '=' if there is no space between RHS and '='
- if (colon && colon[0] == ':')
- PropertyDotString += " ";
- SourceRange Range(BegLoc, EndLoc);
- commit.replace(Range, PropertyDotString);
- // remove '[' ']'
- commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
- commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
- }
- return true;
- }
- class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
- ObjCMigrateASTConsumer &Consumer;
- ParentMap &PMap;
- public:
- ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
- : Consumer(consumer), PMap(PMap) { }
- bool shouldVisitTemplateInstantiations() const { return false; }
- bool shouldWalkTypesOfTypeLocs() const { return false; }
- bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
- edit::Commit commit(*Consumer.Editor);
- edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
- Consumer.Editor->commit(commit);
- }
- if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
- edit::Commit commit(*Consumer.Editor);
- edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
- Consumer.Editor->commit(commit);
- }
- if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) {
- edit::Commit commit(*Consumer.Editor);
- rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
- commit, &PMap);
- Consumer.Editor->commit(commit);
- }
- return true;
- }
- bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
- // Do depth first; we want to rewrite the subexpressions first so that if
- // we have to move expressions we will move them already rewritten.
- for (Stmt *SubStmt : E->children())
- if (!TraverseStmt(SubStmt))
- return false;
- return WalkUpFromObjCMessageExpr(E);
- }
- };
- class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
- ObjCMigrateASTConsumer &Consumer;
- std::unique_ptr<ParentMap> PMap;
- public:
- BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
- bool shouldVisitTemplateInstantiations() const { return false; }
- bool shouldWalkTypesOfTypeLocs() const { return false; }
- bool TraverseStmt(Stmt *S) {
- PMap.reset(new ParentMap(S));
- ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
- return true;
- }
- };
- } // end anonymous namespace
- void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
- if (!D)
- return;
- if (isa<ObjCMethodDecl>(D))
- return; // Wait for the ObjC container declaration.
- BodyMigrator(*this).TraverseDecl(D);
- }
- static void append_attr(std::string &PropertyString, const char *attr,
- bool &LParenAdded) {
- if (!LParenAdded) {
- PropertyString += "(";
- LParenAdded = true;
- }
- else
- PropertyString += ", ";
- PropertyString += attr;
- }
- static
- void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
- const std::string& TypeString,
- const char *name) {
- const char *argPtr = TypeString.c_str();
- int paren = 0;
- while (*argPtr) {
- switch (*argPtr) {
- case '(':
- PropertyString += *argPtr;
- paren++;
- break;
- case ')':
- PropertyString += *argPtr;
- paren--;
- break;
- case '^':
- case '*':
- PropertyString += (*argPtr);
- if (paren == 1) {
- PropertyString += name;
- name = "";
- }
- break;
- default:
- PropertyString += *argPtr;
- break;
- }
- argPtr++;
- }
- }
- static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
- Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
- bool RetainableObject = ArgType->isObjCRetainableType();
- if (RetainableObject &&
- (propertyLifetime == Qualifiers::OCL_Strong
- || propertyLifetime == Qualifiers::OCL_None)) {
- if (const ObjCObjectPointerType *ObjPtrTy =
- ArgType->getAs<ObjCObjectPointerType>()) {
- ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
- if (IDecl &&
- IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
- return "copy";
- else
- return "strong";
- }
- else if (ArgType->isBlockPointerType())
- return "copy";
- } else if (propertyLifetime == Qualifiers::OCL_Weak)
- // TODO. More precise determination of 'weak' attribute requires
- // looking into setter's implementation for backing weak ivar.
- return "weak";
- else if (RetainableObject)
- return ArgType->isBlockPointerType() ? "copy" : "strong";
- return nullptr;
- }
- static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
- const ObjCMethodDecl *Setter,
- const NSAPI &NS, edit::Commit &commit,
- unsigned LengthOfPrefix,
- bool Atomic, bool UseNsIosOnlyMacro,
- bool AvailabilityArgsMatch) {
- ASTContext &Context = NS.getASTContext();
- bool LParenAdded = false;
- std::string PropertyString = "@property ";
- if (UseNsIosOnlyMacro && NS.isMacroDefined("NS_NONATOMIC_IOSONLY")) {
- PropertyString += "(NS_NONATOMIC_IOSONLY";
- LParenAdded = true;
- } else if (!Atomic) {
- PropertyString += "(nonatomic";
- LParenAdded = true;
- }
- std::string PropertyNameString = Getter->getNameAsString();
- StringRef PropertyName(PropertyNameString);
- if (LengthOfPrefix > 0) {
- if (!LParenAdded) {
- PropertyString += "(getter=";
- LParenAdded = true;
- }
- else
- PropertyString += ", getter=";
- PropertyString += PropertyNameString;
- }
- // Property with no setter may be suggested as a 'readonly' property.
- if (!Setter)
- append_attr(PropertyString, "readonly", LParenAdded);
- // Short circuit 'delegate' properties that contain the name "delegate" or
- // "dataSource", or have exact name "target" to have 'assign' attribute.
- if (PropertyName.equals("target") || PropertyName.contains("delegate") ||
- PropertyName.contains("dataSource")) {
- QualType QT = Getter->getReturnType();
- if (!QT->isRealType())
- append_attr(PropertyString, "assign", LParenAdded);
- } else if (!Setter) {
- QualType ResType = Context.getCanonicalType(Getter->getReturnType());
- if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
- append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
- } else {
- const ParmVarDecl *argDecl = *Setter->param_begin();
- QualType ArgType = Context.getCanonicalType(argDecl->getType());
- if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
- append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
- }
- if (LParenAdded)
- PropertyString += ')';
- QualType RT = Getter->getReturnType();
- if (!isa<TypedefType>(RT)) {
- // strip off any ARC lifetime qualifier.
- QualType CanResultTy = Context.getCanonicalType(RT);
- if (CanResultTy.getQualifiers().hasObjCLifetime()) {
- Qualifiers Qs = CanResultTy.getQualifiers();
- Qs.removeObjCLifetime();
- RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
- }
- }
- PropertyString += " ";
- PrintingPolicy SubPolicy(Context.getPrintingPolicy());
- SubPolicy.SuppressStrongLifetime = true;
- SubPolicy.SuppressLifetimeQualifiers = true;
- std::string TypeString = RT.getAsString(SubPolicy);
- if (LengthOfPrefix > 0) {
- // property name must strip off "is" and lower case the first character
- // after that; e.g. isContinuous will become continuous.
- StringRef PropertyNameStringRef(PropertyNameString);
- PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
- PropertyNameString = std::string(PropertyNameStringRef);
- bool NoLowering = (isUppercase(PropertyNameString[0]) &&
- PropertyNameString.size() > 1 &&
- isUppercase(PropertyNameString[1]));
- if (!NoLowering)
- PropertyNameString[0] = toLowercase(PropertyNameString[0]);
- }
- if (RT->isBlockPointerType() || RT->isFunctionPointerType())
- MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
- TypeString,
- PropertyNameString.c_str());
- else {
- char LastChar = TypeString[TypeString.size()-1];
- PropertyString += TypeString;
- if (LastChar != '*')
- PropertyString += ' ';
- PropertyString += PropertyNameString;
- }
- SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
- Selector GetterSelector = Getter->getSelector();
- SourceLocation EndGetterSelectorLoc =
- StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
- commit.replace(CharSourceRange::getCharRange(Getter->getBeginLoc(),
- EndGetterSelectorLoc),
- PropertyString);
- if (Setter && AvailabilityArgsMatch) {
- SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
- // Get location past ';'
- EndLoc = EndLoc.getLocWithOffset(1);
- SourceLocation BeginOfSetterDclLoc = Setter->getBeginLoc();
- // FIXME. This assumes that setter decl; is immediately preceded by eoln.
- // It is trying to remove the setter method decl. line entirely.
- BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
- commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
- }
- }
- static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) {
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
- StringRef Name = CatDecl->getName();
- return Name.endswith("Deprecated");
- }
- return false;
- }
- void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx,
- ObjCContainerDecl *D) {
- if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D))
- return;
- for (auto *Method : D->methods()) {
- if (Method->isDeprecated())
- continue;
- bool PropertyInferred = migrateProperty(Ctx, D, Method);
- // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
- // the getter method as it ends up on the property itself which we don't want
- // to do unless -objcmt-returns-innerpointer-property option is on.
- if (!PropertyInferred ||
- (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
- migrateNsReturnsInnerPointer(Ctx, Method);
- }
- if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
- return;
- for (auto *Prop : D->instance_properties()) {
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
- !Prop->isDeprecated())
- migratePropertyNsReturnsInnerPointer(Ctx, Prop);
- }
- }
- static bool
- ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
- const ObjCImplementationDecl *ImpDecl,
- const ObjCInterfaceDecl *IDecl,
- ObjCProtocolDecl *Protocol) {
- // In auto-synthesis, protocol properties are not synthesized. So,
- // a conforming protocol must have its required properties declared
- // in class interface.
- bool HasAtleastOneRequiredProperty = false;
- if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
- for (const auto *Property : PDecl->instance_properties()) {
- if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
- continue;
- HasAtleastOneRequiredProperty = true;
- DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName());
- if (R.empty()) {
- // Relax the rule and look into class's implementation for a synthesize
- // or dynamic declaration. Class is implementing a property coming from
- // another protocol. This still makes the target protocol as conforming.
- if (!ImpDecl->FindPropertyImplDecl(
- Property->getDeclName().getAsIdentifierInfo(),
- Property->getQueryKind()))
- return false;
- } else if (auto *ClassProperty = R.find_first<ObjCPropertyDecl>()) {
- if ((ClassProperty->getPropertyAttributes() !=
- Property->getPropertyAttributes()) ||
- !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
- return false;
- } else
- return false;
- }
- // At this point, all required properties in this protocol conform to those
- // declared in the class.
- // Check that class implements the required methods of the protocol too.
- bool HasAtleastOneRequiredMethod = false;
- if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
- if (PDecl->meth_begin() == PDecl->meth_end())
- return HasAtleastOneRequiredProperty;
- for (const auto *MD : PDecl->methods()) {
- if (MD->isImplicit())
- continue;
- if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
- continue;
- DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName());
- if (R.empty())
- return false;
- bool match = false;
- HasAtleastOneRequiredMethod = true;
- for (NamedDecl *ND : R)
- if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(ND))
- if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
- match = true;
- break;
- }
- if (!match)
- return false;
- }
- }
- return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
- }
- static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
- llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
- const NSAPI &NS, edit::Commit &commit) {
- const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
- std::string ClassString;
- SourceLocation EndLoc =
- IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
- if (Protocols.empty()) {
- ClassString = '<';
- for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
- ClassString += ConformingProtocols[i]->getNameAsString();
- if (i != (e-1))
- ClassString += ", ";
- }
- ClassString += "> ";
- }
- else {
- ClassString = ", ";
- for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
- ClassString += ConformingProtocols[i]->getNameAsString();
- if (i != (e-1))
- ClassString += ", ";
- }
- ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
- EndLoc = *PL;
- }
- commit.insertAfterToken(EndLoc, ClassString);
- return true;
- }
- static StringRef GetUnsignedName(StringRef NSIntegerName) {
- StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
- .Case("int8_t", "uint8_t")
- .Case("int16_t", "uint16_t")
- .Case("int32_t", "uint32_t")
- .Case("NSInteger", "NSUInteger")
- .Case("int64_t", "uint64_t")
- .Default(NSIntegerName);
- return UnsignedName;
- }
- static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
- const TypedefDecl *TypedefDcl,
- const NSAPI &NS, edit::Commit &commit,
- StringRef NSIntegerName,
- bool NSOptions) {
- std::string ClassString;
- if (NSOptions) {
- ClassString = "typedef NS_OPTIONS(";
- ClassString += GetUnsignedName(NSIntegerName);
- }
- else {
- ClassString = "typedef NS_ENUM(";
- ClassString += NSIntegerName;
- }
- ClassString += ", ";
- ClassString += TypedefDcl->getIdentifier()->getName();
- ClassString += ')';
- SourceRange R(EnumDcl->getBeginLoc(), EnumDcl->getBeginLoc());
- commit.replace(R, ClassString);
- SourceLocation EndOfEnumDclLoc = EnumDcl->getEndLoc();
- EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
- NS.getASTContext(), /*IsDecl*/true);
- if (EndOfEnumDclLoc.isValid()) {
- SourceRange EnumDclRange(EnumDcl->getBeginLoc(), EndOfEnumDclLoc);
- commit.insertFromRange(TypedefDcl->getBeginLoc(), EnumDclRange);
- }
- else
- return false;
- SourceLocation EndTypedefDclLoc = TypedefDcl->getEndLoc();
- EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
- NS.getASTContext(), /*IsDecl*/true);
- if (EndTypedefDclLoc.isValid()) {
- SourceRange TDRange(TypedefDcl->getBeginLoc(), EndTypedefDclLoc);
- commit.remove(TDRange);
- }
- else
- return false;
- EndOfEnumDclLoc =
- trans::findLocationAfterSemi(EnumDcl->getEndLoc(), NS.getASTContext(),
- /*IsDecl*/ true);
- if (EndOfEnumDclLoc.isValid()) {
- SourceLocation BeginOfEnumDclLoc = EnumDcl->getBeginLoc();
- // FIXME. This assumes that enum decl; is immediately preceded by eoln.
- // It is trying to remove the enum decl. lines entirely.
- BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
- commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
- return true;
- }
- return false;
- }
- static void rewriteToNSMacroDecl(ASTContext &Ctx,
- const EnumDecl *EnumDcl,
- const TypedefDecl *TypedefDcl,
- const NSAPI &NS, edit::Commit &commit,
- bool IsNSIntegerType) {
- QualType DesignatedEnumType = EnumDcl->getIntegerType();
- assert(!DesignatedEnumType.isNull()
- && "rewriteToNSMacroDecl - underlying enum type is null");
- PrintingPolicy Policy(Ctx.getPrintingPolicy());
- std::string TypeString = DesignatedEnumType.getAsString(Policy);
- std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
- ClassString += TypeString;
- ClassString += ", ";
- ClassString += TypedefDcl->getIdentifier()->getName();
- ClassString += ") ";
- SourceLocation EndLoc = EnumDcl->getBraceRange().getBegin();
- if (EndLoc.isInvalid())
- return;
- CharSourceRange R =
- CharSourceRange::getCharRange(EnumDcl->getBeginLoc(), EndLoc);
- commit.replace(R, ClassString);
- // This is to remove spaces between '}' and typedef name.
- SourceLocation StartTypedefLoc = EnumDcl->getEndLoc();
- StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1);
- SourceLocation EndTypedefLoc = TypedefDcl->getEndLoc();
- commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc));
- }
- static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
- const EnumDecl *EnumDcl) {
- bool PowerOfTwo = true;
- bool AllHexdecimalEnumerator = true;
- uint64_t MaxPowerOfTwoVal = 0;
- for (auto Enumerator : EnumDcl->enumerators()) {
- const Expr *InitExpr = Enumerator->getInitExpr();
- if (!InitExpr) {
- PowerOfTwo = false;
- AllHexdecimalEnumerator = false;
- continue;
- }
- InitExpr = InitExpr->IgnoreParenCasts();
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
- if (BO->isShiftOp() || BO->isBitwiseOp())
- return true;
- uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
- if (PowerOfTwo && EnumVal) {
- if (!llvm::isPowerOf2_64(EnumVal))
- PowerOfTwo = false;
- else if (EnumVal > MaxPowerOfTwoVal)
- MaxPowerOfTwoVal = EnumVal;
- }
- if (AllHexdecimalEnumerator && EnumVal) {
- bool FoundHexdecimalEnumerator = false;
- SourceLocation EndLoc = Enumerator->getEndLoc();
- Token Tok;
- if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
- if (Tok.isLiteral() && Tok.getLength() > 2) {
- if (const char *StringLit = Tok.getLiteralData())
- FoundHexdecimalEnumerator =
- (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
- }
- if (!FoundHexdecimalEnumerator)
- AllHexdecimalEnumerator = false;
- }
- }
- return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
- }
- void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
- const ObjCImplementationDecl *ImpDecl) {
- const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
- if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
- return;
- // Find all implicit conforming protocols for this class
- // and make them explicit.
- llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
- Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
- llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
- for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls)
- if (!ExplicitProtocols.count(ProtDecl))
- PotentialImplicitProtocols.push_back(ProtDecl);
- if (PotentialImplicitProtocols.empty())
- return;
- // go through list of non-optional methods and properties in each protocol
- // in the PotentialImplicitProtocols list. If class implements every one of the
- // methods and properties, then this class conforms to this protocol.
- llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
- for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
- if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
- PotentialImplicitProtocols[i]))
- ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
- if (ConformingProtocols.empty())
- return;
- // Further reduce number of conforming protocols. If protocol P1 is in the list
- // protocol P2 (P2<P1>), No need to include P1.
- llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
- for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
- bool DropIt = false;
- ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
- for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
- ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
- if (PDecl == TargetPDecl)
- continue;
- if (PDecl->lookupProtocolNamed(
- TargetPDecl->getDeclName().getAsIdentifierInfo())) {
- DropIt = true;
- break;
- }
- }
- if (!DropIt)
- MinimalConformingProtocols.push_back(TargetPDecl);
- }
- if (MinimalConformingProtocols.empty())
- return;
- edit::Commit commit(*Editor);
- rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
- *NSAPIObj, commit);
- Editor->commit(commit);
- }
- void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
- const TypedefDecl *TypedefDcl) {
- QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
- if (NSAPIObj->isObjCNSIntegerType(qt))
- NSIntegerTypedefed = TypedefDcl;
- else if (NSAPIObj->isObjCNSUIntegerType(qt))
- NSUIntegerTypedefed = TypedefDcl;
- }
- bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
- const EnumDecl *EnumDcl,
- const TypedefDecl *TypedefDcl) {
- if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
- EnumDcl->isDeprecated())
- return false;
- if (!TypedefDcl) {
- if (NSIntegerTypedefed) {
- TypedefDcl = NSIntegerTypedefed;
- NSIntegerTypedefed = nullptr;
- }
- else if (NSUIntegerTypedefed) {
- TypedefDcl = NSUIntegerTypedefed;
- NSUIntegerTypedefed = nullptr;
- }
- else
- return false;
- FileID FileIdOfTypedefDcl =
- PP.getSourceManager().getFileID(TypedefDcl->getLocation());
- FileID FileIdOfEnumDcl =
- PP.getSourceManager().getFileID(EnumDcl->getLocation());
- if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
- return false;
- }
- if (TypedefDcl->isDeprecated())
- return false;
- QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
- StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
- if (NSIntegerName.empty()) {
- // Also check for typedef enum {...} TD;
- if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
- if (EnumTy->getDecl() == EnumDcl) {
- bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
- if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
- return false;
- edit::Commit commit(*Editor);
- rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
- Editor->commit(commit);
- return true;
- }
- }
- return false;
- }
- // We may still use NS_OPTIONS based on what we find in the enumertor list.
- bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
- if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
- return false;
- edit::Commit commit(*Editor);
- bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
- commit, NSIntegerName, NSOptions);
- Editor->commit(commit);
- return Res;
- }
- static void ReplaceWithInstancetype(ASTContext &Ctx,
- const ObjCMigrateASTConsumer &ASTC,
- ObjCMethodDecl *OM) {
- if (OM->getReturnType() == Ctx.getObjCInstanceType())
- return; // already has instancetype.
- SourceRange R;
- std::string ClassString;
- if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
- TypeLoc TL = TSInfo->getTypeLoc();
- R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
- ClassString = "instancetype";
- }
- else {
- R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
- ClassString = OM->isInstanceMethod() ? '-' : '+';
- ClassString += " (instancetype)";
- }
- edit::Commit commit(*ASTC.Editor);
- commit.replace(R, ClassString);
- ASTC.Editor->commit(commit);
- }
- static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
- ObjCMethodDecl *OM) {
- ObjCInterfaceDecl *IDecl = OM->getClassInterface();
- SourceRange R;
- std::string ClassString;
- if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
- TypeLoc TL = TSInfo->getTypeLoc();
- R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
- ClassString = std::string(IDecl->getName());
- ClassString += "*";
- }
- }
- else {
- R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
- ClassString = "+ (";
- ClassString += IDecl->getName(); ClassString += "*)";
- }
- edit::Commit commit(*ASTC.Editor);
- commit.replace(R, ClassString);
- ASTC.Editor->commit(commit);
- }
- void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
- ObjCContainerDecl *CDecl,
- ObjCMethodDecl *OM) {
- ObjCInstanceTypeFamily OIT_Family =
- Selector::getInstTypeMethodFamily(OM->getSelector());
- std::string ClassName;
- switch (OIT_Family) {
- case OIT_None:
- migrateFactoryMethod(Ctx, CDecl, OM);
- return;
- case OIT_Array:
- ClassName = "NSArray";
- break;
- case OIT_Dictionary:
- ClassName = "NSDictionary";
- break;
- case OIT_Singleton:
- migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
- return;
- case OIT_Init:
- if (OM->getReturnType()->isObjCIdType())
- ReplaceWithInstancetype(Ctx, *this, OM);
- return;
- case OIT_ReturnsSelf:
- migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
- return;
- }
- if (!OM->getReturnType()->isObjCIdType())
- return;
- ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
- if (!IDecl) {
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
- IDecl = CatDecl->getClassInterface();
- else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
- IDecl = ImpDecl->getClassInterface();
- }
- if (!IDecl ||
- !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
- migrateFactoryMethod(Ctx, CDecl, OM);
- return;
- }
- ReplaceWithInstancetype(Ctx, *this, OM);
- }
- static bool TypeIsInnerPointer(QualType T) {
- if (!T->isAnyPointerType())
- return false;
- if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
- T->isBlockPointerType() || T->isFunctionPointerType() ||
- ento::coreFoundation::isCFObjectRef(T))
- return false;
- // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
- // is not an innter pointer type.
- QualType OrigT = T;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
- T = TD->getDecl()->getUnderlyingType();
- if (OrigT == T || !T->isPointerType())
- return true;
- const PointerType* PT = T->getAs<PointerType>();
- QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
- if (UPointeeT->isRecordType()) {
- const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
- if (!RecordTy->getDecl()->isCompleteDefinition())
- return false;
- }
- return true;
- }
- /// Check whether the two versions match.
- static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
- return (X == Y);
- }
- /// AvailabilityAttrsMatch - This routine checks that if comparing two
- /// availability attributes, all their components match. It returns
- /// true, if not dealing with availability or when all components of
- /// availability attributes match. This routine is only called when
- /// the attributes are of the same kind.
- static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
- const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
- if (!AA1)
- return true;
- const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
- VersionTuple Introduced1 = AA1->getIntroduced();
- VersionTuple Deprecated1 = AA1->getDeprecated();
- VersionTuple Obsoleted1 = AA1->getObsoleted();
- bool IsUnavailable1 = AA1->getUnavailable();
- VersionTuple Introduced2 = AA2->getIntroduced();
- VersionTuple Deprecated2 = AA2->getDeprecated();
- VersionTuple Obsoleted2 = AA2->getObsoleted();
- bool IsUnavailable2 = AA2->getUnavailable();
- return (versionsMatch(Introduced1, Introduced2) &&
- versionsMatch(Deprecated1, Deprecated2) &&
- versionsMatch(Obsoleted1, Obsoleted2) &&
- IsUnavailable1 == IsUnavailable2);
- }
- static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
- bool &AvailabilityArgsMatch) {
- // This list is very small, so this need not be optimized.
- for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
- bool match = false;
- for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
- // Matching attribute kind only. Except for Availability attributes,
- // we are not getting into details of the attributes. For all practical purposes
- // this is sufficient.
- if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
- if (AvailabilityArgsMatch)
- AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
- match = true;
- break;
- }
- }
- if (!match)
- return false;
- }
- return true;
- }
- /// AttributesMatch - This routine checks list of attributes for two
- /// decls. It returns false, if there is a mismatch in kind of
- /// attributes seen in the decls. It returns true if the two decls
- /// have list of same kind of attributes. Furthermore, when there
- /// are availability attributes in the two decls, it sets the
- /// AvailabilityArgsMatch to false if availability attributes have
- /// different versions, etc.
- static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
- bool &AvailabilityArgsMatch) {
- if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
- AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
- return true;
- }
- AvailabilityArgsMatch = true;
- const AttrVec &Attrs1 = Decl1->getAttrs();
- const AttrVec &Attrs2 = Decl2->getAttrs();
- bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
- if (match && (Attrs2.size() > Attrs1.size()))
- return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
- return match;
- }
- static bool IsValidIdentifier(ASTContext &Ctx,
- const char *Name) {
- if (!isAsciiIdentifierStart(Name[0]))
- return false;
- std::string NameString = Name;
- NameString[0] = toLowercase(NameString[0]);
- IdentifierInfo *II = &Ctx.Idents.get(NameString);
- return II->getTokenID() == tok::identifier;
- }
- bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
- ObjCContainerDecl *D,
- ObjCMethodDecl *Method) {
- if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
- Method->param_size() != 0)
- return false;
- // Is this method candidate to be a getter?
- QualType GRT = Method->getReturnType();
- if (GRT->isVoidType())
- return false;
- Selector GetterSelector = Method->getSelector();
- ObjCInstanceTypeFamily OIT_Family =
- Selector::getInstTypeMethodFamily(GetterSelector);
- if (OIT_Family != OIT_None)
- return false;
- IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
- Selector SetterSelector =
- SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
- getterName);
- ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
- unsigned LengthOfPrefix = 0;
- if (!SetterMethod) {
- // try a different naming convention for getter: isXxxxx
- StringRef getterNameString = getterName->getName();
- bool IsPrefix = getterNameString.startswith("is");
- // Note that we don't want to change an isXXX method of retainable object
- // type to property (readonly or otherwise).
- if (IsPrefix && GRT->isObjCRetainableType())
- return false;
- if (IsPrefix || getterNameString.startswith("get")) {
- LengthOfPrefix = (IsPrefix ? 2 : 3);
- const char *CGetterName = getterNameString.data() + LengthOfPrefix;
- // Make sure that first character after "is" or "get" prefix can
- // start an identifier.
- if (!IsValidIdentifier(Ctx, CGetterName))
- return false;
- if (CGetterName[0] && isUppercase(CGetterName[0])) {
- getterName = &Ctx.Idents.get(CGetterName);
- SetterSelector =
- SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
- getterName);
- SetterMethod = D->getInstanceMethod(SetterSelector);
- }
- }
- }
- if (SetterMethod) {
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
- return false;
- bool AvailabilityArgsMatch;
- if (SetterMethod->isDeprecated() ||
- !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
- return false;
- // Is this a valid setter, matching the target getter?
- QualType SRT = SetterMethod->getReturnType();
- if (!SRT->isVoidType())
- return false;
- const ParmVarDecl *argDecl = *SetterMethod->param_begin();
- QualType ArgType = argDecl->getType();
- if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
- return false;
- edit::Commit commit(*Editor);
- rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
- LengthOfPrefix,
- (ASTMigrateActions &
- FrontendOptions::ObjCMT_AtomicProperty) != 0,
- (ASTMigrateActions &
- FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
- AvailabilityArgsMatch);
- Editor->commit(commit);
- return true;
- }
- else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
- // Try a non-void method with no argument (and no setter or property of same name
- // as a 'readonly' property.
- edit::Commit commit(*Editor);
- rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
- LengthOfPrefix,
- (ASTMigrateActions &
- FrontendOptions::ObjCMT_AtomicProperty) != 0,
- (ASTMigrateActions &
- FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
- /*AvailabilityArgsMatch*/false);
- Editor->commit(commit);
- return true;
- }
- return false;
- }
- void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
- ObjCMethodDecl *OM) {
- if (OM->isImplicit() ||
- !OM->isInstanceMethod() ||
- OM->hasAttr<ObjCReturnsInnerPointerAttr>())
- return;
- QualType RT = OM->getReturnType();
- if (!TypeIsInnerPointer(RT) ||
- !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
- return;
- edit::Commit commit(*Editor);
- commit.insertBefore(OM->getEndLoc(), " NS_RETURNS_INNER_POINTER");
- Editor->commit(commit);
- }
- void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
- ObjCPropertyDecl *P) {
- QualType T = P->getType();
- if (!TypeIsInnerPointer(T) ||
- !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
- return;
- edit::Commit commit(*Editor);
- commit.insertBefore(P->getEndLoc(), " NS_RETURNS_INNER_POINTER ");
- Editor->commit(commit);
- }
- void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
- ObjCContainerDecl *CDecl) {
- if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
- return;
- // migrate methods which can have instancetype as their result type.
- for (auto *Method : CDecl->methods()) {
- if (Method->isDeprecated())
- continue;
- migrateMethodInstanceType(Ctx, CDecl, Method);
- }
- }
- void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
- ObjCContainerDecl *CDecl,
- ObjCMethodDecl *OM,
- ObjCInstanceTypeFamily OIT_Family) {
- if (OM->isInstanceMethod() ||
- OM->getReturnType() == Ctx.getObjCInstanceType() ||
- !OM->getReturnType()->isObjCIdType())
- return;
- // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
- // NSYYYNamE with matching names be at least 3 characters long.
- ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
- if (!IDecl) {
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
- IDecl = CatDecl->getClassInterface();
- else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
- IDecl = ImpDecl->getClassInterface();
- }
- if (!IDecl)
- return;
- std::string StringClassName = std::string(IDecl->getName());
- StringRef LoweredClassName(StringClassName);
- std::string StringLoweredClassName = LoweredClassName.lower();
- LoweredClassName = StringLoweredClassName;
- IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
- // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
- if (!MethodIdName)
- return;
- std::string MethodName = std::string(MethodIdName->getName());
- if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
- StringRef STRefMethodName(MethodName);
- size_t len = 0;
- if (STRefMethodName.startswith("standard"))
- len = strlen("standard");
- else if (STRefMethodName.startswith("shared"))
- len = strlen("shared");
- else if (STRefMethodName.startswith("default"))
- len = strlen("default");
- else
- return;
- MethodName = std::string(STRefMethodName.substr(len));
- }
- std::string MethodNameSubStr = MethodName.substr(0, 3);
- StringRef MethodNamePrefix(MethodNameSubStr);
- std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
- MethodNamePrefix = StringLoweredMethodNamePrefix;
- size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
- if (Ix == StringRef::npos)
- return;
- std::string ClassNamePostfix = std::string(LoweredClassName.substr(Ix));
- StringRef LoweredMethodName(MethodName);
- std::string StringLoweredMethodName = LoweredMethodName.lower();
- LoweredMethodName = StringLoweredMethodName;
- if (!LoweredMethodName.startswith(ClassNamePostfix))
- return;
- if (OIT_Family == OIT_ReturnsSelf)
- ReplaceWithClasstype(*this, OM);
- else
- ReplaceWithInstancetype(Ctx, *this, OM);
- }
- static bool IsVoidStarType(QualType Ty) {
- if (!Ty->isPointerType())
- return false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
- Ty = TD->getDecl()->getUnderlyingType();
- // Is the type void*?
- const PointerType* PT = Ty->castAs<PointerType>();
- if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
- return true;
- return IsVoidStarType(PT->getPointeeType());
- }
- /// AuditedType - This routine audits the type AT and returns false if it is one of known
- /// CF object types or of the "void *" variety. It returns true if we don't care about the type
- /// such as a non-pointer or pointers which have no ownership issues (such as "int *").
- static bool AuditedType (QualType AT) {
- if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
- return true;
- // FIXME. There isn't much we can say about CF pointer type; or is there?
- if (ento::coreFoundation::isCFObjectRef(AT) ||
- IsVoidStarType(AT) ||
- // If an ObjC object is type, assuming that it is not a CF function and
- // that it is an un-audited function.
- AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
- return false;
- // All other pointers are assumed audited as harmless.
- return true;
- }
- void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
- if (CFFunctionIBCandidates.empty())
- return;
- if (!NSAPIObj->isMacroDefined("CF_IMPLICIT_BRIDGING_ENABLED")) {
- CFFunctionIBCandidates.clear();
- FileId = FileID();
- return;
- }
- // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
- const Decl *FirstFD = CFFunctionIBCandidates[0];
- const Decl *LastFD =
- CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
- const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
- edit::Commit commit(*Editor);
- commit.insertBefore(FirstFD->getBeginLoc(), PragmaString);
- PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
- SourceLocation EndLoc = LastFD->getEndLoc();
- // get location just past end of function location.
- EndLoc = PP.getLocForEndOfToken(EndLoc);
- if (isa<FunctionDecl>(LastFD)) {
- // For Methods, EndLoc points to the ending semcolon. So,
- // not of these extra work is needed.
- Token Tok;
- // get locaiton of token that comes after end of function.
- bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
- if (!Failed)
- EndLoc = Tok.getLocation();
- }
- commit.insertAfterToken(EndLoc, PragmaString);
- Editor->commit(commit);
- FileId = FileID();
- CFFunctionIBCandidates.clear();
- }
- void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
- if (Decl->isDeprecated())
- return;
- if (Decl->hasAttr<CFAuditedTransferAttr>()) {
- assert(CFFunctionIBCandidates.empty() &&
- "Cannot have audited functions/methods inside user "
- "provided CF_IMPLICIT_BRIDGING_ENABLE");
- return;
- }
- // Finction must be annotated first.
- if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
- CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
- if (AuditKind == CF_BRIDGING_ENABLE) {
- CFFunctionIBCandidates.push_back(Decl);
- if (FileId.isInvalid())
- FileId = PP.getSourceManager().getFileID(Decl->getLocation());
- }
- else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
- if (!CFFunctionIBCandidates.empty()) {
- CFFunctionIBCandidates.push_back(Decl);
- if (FileId.isInvalid())
- FileId = PP.getSourceManager().getFileID(Decl->getLocation());
- }
- }
- else
- AnnotateImplicitBridging(Ctx);
- }
- else {
- migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
- AnnotateImplicitBridging(Ctx);
- }
- }
- void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
- const RetainSummary *RS,
- const FunctionDecl *FuncDecl,
- bool ResultAnnotated) {
- // Annotate function.
- if (!ResultAnnotated) {
- RetEffect Ret = RS->getRetEffect();
- const char *AnnotationString = nullptr;
- if (Ret.getObjKind() == ObjKind::CF) {
- if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
- AnnotationString = " CF_RETURNS_RETAINED";
- else if (Ret.notOwned() &&
- NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
- AnnotationString = " CF_RETURNS_NOT_RETAINED";
- }
- else if (Ret.getObjKind() == ObjKind::ObjC) {
- if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
- AnnotationString = " NS_RETURNS_RETAINED";
- }
- if (AnnotationString) {
- edit::Commit commit(*Editor);
- commit.insertAfterToken(FuncDecl->getEndLoc(), AnnotationString);
- Editor->commit(commit);
- }
- }
- unsigned i = 0;
- for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
- pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
- const ParmVarDecl *pd = *pi;
- ArgEffect AE = RS->getArg(i);
- if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF &&
- !pd->hasAttr<CFConsumedAttr>() &&
- NSAPIObj->isMacroDefined("CF_CONSUMED")) {
- edit::Commit commit(*Editor);
- commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
- Editor->commit(commit);
- } else if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::ObjC &&
- !pd->hasAttr<NSConsumedAttr>() &&
- NSAPIObj->isMacroDefined("NS_CONSUMED")) {
- edit::Commit commit(*Editor);
- commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
- Editor->commit(commit);
- }
- }
- }
- ObjCMigrateASTConsumer::CF_BRIDGING_KIND
- ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
- ASTContext &Ctx,
- const FunctionDecl *FuncDecl) {
- if (FuncDecl->hasBody())
- return CF_BRIDGING_NONE;
- const RetainSummary *RS =
- getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl));
- bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
- FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
- FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
- FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
- FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
- // Trivial case of when function is annotated and has no argument.
- if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
- return CF_BRIDGING_NONE;
- bool ReturnCFAudited = false;
- if (!FuncIsReturnAnnotated) {
- RetEffect Ret = RS->getRetEffect();
- if (Ret.getObjKind() == ObjKind::CF &&
- (Ret.isOwned() || Ret.notOwned()))
- ReturnCFAudited = true;
- else if (!AuditedType(FuncDecl->getReturnType()))
- return CF_BRIDGING_NONE;
- }
- // At this point result type is audited for potential inclusion.
- unsigned i = 0;
- bool ArgCFAudited = false;
- for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
- pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
- const ParmVarDecl *pd = *pi;
- ArgEffect AE = RS->getArg(i);
- if ((AE.getKind() == DecRef /*CFConsumed annotated*/ ||
- AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) {
- if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>())
- ArgCFAudited = true;
- else if (AE.getKind() == IncRef)
- ArgCFAudited = true;
- } else {
- QualType AT = pd->getType();
- if (!AuditedType(AT)) {
- AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
- return CF_BRIDGING_NONE;
- }
- }
- }
- if (ReturnCFAudited || ArgCFAudited)
- return CF_BRIDGING_ENABLE;
- return CF_BRIDGING_MAY_INCLUDE;
- }
- void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
- ObjCContainerDecl *CDecl) {
- if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
- return;
- // migrate methods which can have instancetype as their result type.
- for (const auto *Method : CDecl->methods())
- migrateCFAnnotation(Ctx, Method);
- }
- void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
- const RetainSummary *RS,
- const ObjCMethodDecl *MethodDecl,
- bool ResultAnnotated) {
- // Annotate function.
- if (!ResultAnnotated) {
- RetEffect Ret = RS->getRetEffect();
- const char *AnnotationString = nullptr;
- if (Ret.getObjKind() == ObjKind::CF) {
- if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
- AnnotationString = " CF_RETURNS_RETAINED";
- else if (Ret.notOwned() &&
- NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
- AnnotationString = " CF_RETURNS_NOT_RETAINED";
- }
- else if (Ret.getObjKind() == ObjKind::ObjC) {
- ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
- switch (OMF) {
- case clang::OMF_alloc:
- case clang::OMF_new:
- case clang::OMF_copy:
- case clang::OMF_init:
- case clang::OMF_mutableCopy:
- break;
- default:
- if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
- AnnotationString = " NS_RETURNS_RETAINED";
- break;
- }
- }
- if (AnnotationString) {
- edit::Commit commit(*Editor);
- commit.insertBefore(MethodDecl->getEndLoc(), AnnotationString);
- Editor->commit(commit);
- }
- }
- unsigned i = 0;
- for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
- pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
- const ParmVarDecl *pd = *pi;
- ArgEffect AE = RS->getArg(i);
- if (AE.getKind() == DecRef
- && AE.getObjKind() == ObjKind::CF
- && !pd->hasAttr<CFConsumedAttr>() &&
- NSAPIObj->isMacroDefined("CF_CONSUMED")) {
- edit::Commit commit(*Editor);
- commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
- Editor->commit(commit);
- }
- }
- }
- void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
- ASTContext &Ctx,
- const ObjCMethodDecl *MethodDecl) {
- if (MethodDecl->hasBody() || MethodDecl->isImplicit())
- return;
- const RetainSummary *RS =
- getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl));
- bool MethodIsReturnAnnotated =
- (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
- MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
- MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
- MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
- MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
- if (RS->getReceiverEffect().getKind() == DecRef &&
- !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
- MethodDecl->getMethodFamily() != OMF_init &&
- MethodDecl->getMethodFamily() != OMF_release &&
- NSAPIObj->isMacroDefined("NS_CONSUMES_SELF")) {
- edit::Commit commit(*Editor);
- commit.insertBefore(MethodDecl->getEndLoc(), " NS_CONSUMES_SELF");
- Editor->commit(commit);
- }
- // Trivial case of when function is annotated and has no argument.
- if (MethodIsReturnAnnotated &&
- (MethodDecl->param_begin() == MethodDecl->param_end()))
- return;
- if (!MethodIsReturnAnnotated) {
- RetEffect Ret = RS->getRetEffect();
- if ((Ret.getObjKind() == ObjKind::CF ||
- Ret.getObjKind() == ObjKind::ObjC) &&
- (Ret.isOwned() || Ret.notOwned())) {
- AddCFAnnotations(Ctx, RS, MethodDecl, false);
- return;
- } else if (!AuditedType(MethodDecl->getReturnType()))
- return;
- }
- // At this point result type is either annotated or audited.
- unsigned i = 0;
- for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
- pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
- const ParmVarDecl *pd = *pi;
- ArgEffect AE = RS->getArg(i);
- if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) ||
- AE.getKind() == IncRef || !AuditedType(pd->getType())) {
- AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
- return;
- }
- }
- }
- namespace {
- class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> {
- public:
- bool shouldVisitTemplateInstantiations() const { return false; }
- bool shouldWalkTypesOfTypeLocs() const { return false; }
- bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
- if (E->getMethodFamily() == OMF_init)
- return false;
- }
- return true;
- }
- };
- } // end anonymous namespace
- static bool hasSuperInitCall(const ObjCMethodDecl *MD) {
- return !SuperInitChecker().TraverseStmt(MD->getBody());
- }
- void ObjCMigrateASTConsumer::inferDesignatedInitializers(
- ASTContext &Ctx,
- const ObjCImplementationDecl *ImplD) {
- const ObjCInterfaceDecl *IFace = ImplD->getClassInterface();
- if (!IFace || IFace->hasDesignatedInitializers())
- return;
- if (!NSAPIObj->isMacroDefined("NS_DESIGNATED_INITIALIZER"))
- return;
- for (const auto *MD : ImplD->instance_methods()) {
- if (MD->isDeprecated() ||
- MD->getMethodFamily() != OMF_init ||
- MD->isDesignatedInitializerForTheInterface())
- continue;
- const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(),
- /*isInstance=*/true);
- if (!IFaceM)
- continue;
- if (hasSuperInitCall(MD)) {
- edit::Commit commit(*Editor);
- commit.insert(IFaceM->getEndLoc(), " NS_DESIGNATED_INITIALIZER");
- Editor->commit(commit);
- }
- }
- }
- bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx,
- SourceLocation Loc) {
- if (FoundationIncluded)
- return true;
- if (Loc.isInvalid())
- return false;
- auto *nsEnumId = &Ctx.Idents.get("NS_ENUM");
- if (PP.getMacroDefinitionAtLoc(nsEnumId, Loc)) {
- FoundationIncluded = true;
- return true;
- }
- edit::Commit commit(*Editor);
- if (Ctx.getLangOpts().Modules)
- commit.insert(Loc, "#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
- else
- commit.insert(Loc, "#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
- Editor->commit(commit);
- FoundationIncluded = true;
- return true;
- }
- namespace {
- class RewritesReceiver : public edit::EditsReceiver {
- Rewriter &Rewrite;
- public:
- RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
- void insert(SourceLocation loc, StringRef text) override {
- Rewrite.InsertText(loc, text);
- }
- void replace(CharSourceRange range, StringRef text) override {
- Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
- }
- };
- class JSONEditWriter : public edit::EditsReceiver {
- SourceManager &SourceMgr;
- llvm::raw_ostream &OS;
- public:
- JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS)
- : SourceMgr(SM), OS(OS) {
- OS << "[\n";
- }
- ~JSONEditWriter() override { OS << "]\n"; }
- private:
- struct EntryWriter {
- SourceManager &SourceMgr;
- llvm::raw_ostream &OS;
- EntryWriter(SourceManager &SM, llvm::raw_ostream &OS)
- : SourceMgr(SM), OS(OS) {
- OS << " {\n";
- }
- ~EntryWriter() {
- OS << " },\n";
- }
- void writeLoc(SourceLocation Loc) {
- FileID FID;
- unsigned Offset;
- std::tie(FID, Offset) = SourceMgr.getDecomposedLoc(Loc);
- assert(FID.isValid());
- SmallString<200> Path =
- StringRef(SourceMgr.getFileEntryForID(FID)->getName());
- llvm::sys::fs::make_absolute(Path);
- OS << " \"file\": \"";
- OS.write_escaped(Path.str()) << "\",\n";
- OS << " \"offset\": " << Offset << ",\n";
- }
- void writeRemove(CharSourceRange Range) {
- assert(Range.isCharRange());
- std::pair<FileID, unsigned> Begin =
- SourceMgr.getDecomposedLoc(Range.getBegin());
- std::pair<FileID, unsigned> End =
- SourceMgr.getDecomposedLoc(Range.getEnd());
- assert(Begin.first == End.first);
- assert(Begin.second <= End.second);
- unsigned Length = End.second - Begin.second;
- OS << " \"remove\": " << Length << ",\n";
- }
- void writeText(StringRef Text) {
- OS << " \"text\": \"";
- OS.write_escaped(Text) << "\",\n";
- }
- };
- void insert(SourceLocation Loc, StringRef Text) override {
- EntryWriter Writer(SourceMgr, OS);
- Writer.writeLoc(Loc);
- Writer.writeText(Text);
- }
- void replace(CharSourceRange Range, StringRef Text) override {
- EntryWriter Writer(SourceMgr, OS);
- Writer.writeLoc(Range.getBegin());
- Writer.writeRemove(Range);
- Writer.writeText(Text);
- }
- void remove(CharSourceRange Range) override {
- EntryWriter Writer(SourceMgr, OS);
- Writer.writeLoc(Range.getBegin());
- Writer.writeRemove(Range);
- }
- };
- } // end anonymous namespace
- void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
- TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
- if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
- for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
- D != DEnd; ++D) {
- FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
- if (FID.isValid())
- if (FileId.isValid() && FileId != FID) {
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
- AnnotateImplicitBridging(Ctx);
- }
- if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
- if (canModify(CDecl))
- migrateObjCContainerDecl(Ctx, CDecl);
- if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
- if (canModify(CatDecl))
- migrateObjCContainerDecl(Ctx, CatDecl);
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) {
- ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
- if (canModify(PDecl))
- migrateObjCContainerDecl(Ctx, PDecl);
- }
- else if (const ObjCImplementationDecl *ImpDecl =
- dyn_cast<ObjCImplementationDecl>(*D)) {
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) &&
- canModify(ImpDecl))
- migrateProtocolConformance(Ctx, ImpDecl);
- }
- else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
- if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
- continue;
- if (!canModify(ED))
- continue;
- DeclContext::decl_iterator N = D;
- if (++N != DEnd) {
- const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
- if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
- D++;
- }
- else
- migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */nullptr);
- }
- else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
- if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
- continue;
- if (!canModify(TD))
- continue;
- DeclContext::decl_iterator N = D;
- if (++N == DEnd)
- continue;
- if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
- if (canModify(ED)) {
- if (++N != DEnd)
- if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
- // prefer typedef-follows-enum to enum-follows-typedef pattern.
- if (migrateNSEnumDecl(Ctx, ED, TDF)) {
- ++D; ++D;
- CacheObjCNSIntegerTypedefed(TD);
- continue;
- }
- }
- if (migrateNSEnumDecl(Ctx, ED, TD)) {
- ++D;
- continue;
- }
- }
- }
- CacheObjCNSIntegerTypedefed(TD);
- }
- else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
- canModify(FD))
- migrateCFAnnotation(Ctx, FD);
- }
- if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
- bool CanModify = canModify(CDecl);
- // migrate methods which can have instancetype as their result type.
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) &&
- CanModify)
- migrateAllMethodInstaceType(Ctx, CDecl);
- // annotate methods with CF annotations.
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
- CanModify)
- migrateARCSafeAnnotation(Ctx, CDecl);
- }
- if (const ObjCImplementationDecl *
- ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
- if ((ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer) &&
- canModify(ImplD))
- inferDesignatedInitializers(Ctx, ImplD);
- }
- }
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
- AnnotateImplicitBridging(Ctx);
- }
- if (IsOutputFile) {
- std::error_code EC;
- llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
- if (EC) {
- DiagnosticsEngine &Diags = Ctx.getDiagnostics();
- Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
- << EC.message();
- return;
- }
- JSONEditWriter Writer(Ctx.getSourceManager(), OS);
- Editor->applyRewrites(Writer);
- return;
- }
- Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
- RewritesReceiver Rec(rewriter);
- Editor->applyRewrites(Rec);
- for (Rewriter::buffer_iterator
- I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
- FileID FID = I->first;
- RewriteBuffer &buf = I->second;
- Optional<FileEntryRef> file = Ctx.getSourceManager().getFileEntryRefForID(FID);
- assert(file);
- SmallString<512> newText;
- llvm::raw_svector_ostream vecOS(newText);
- buf.write(vecOS);
- std::unique_ptr<llvm::MemoryBuffer> memBuf(
- llvm::MemoryBuffer::getMemBufferCopy(
- StringRef(newText.data(), newText.size()), file->getName()));
- SmallString<64> filePath(file->getName());
- FileMgr.FixupRelativePath(filePath);
- Remapper.remap(filePath.str(), std::move(memBuf));
- }
- if (IsOutputFile) {
- Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
- } else {
- Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
- }
- }
- bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
- CI.getDiagnostics().setIgnoreAllWarnings(true);
- return true;
- }
- static std::vector<std::string> getAllowListFilenames(StringRef DirPath) {
- using namespace llvm::sys::fs;
- using namespace llvm::sys::path;
- std::vector<std::string> Filenames;
- if (DirPath.empty() || !is_directory(DirPath))
- return Filenames;
- std::error_code EC;
- directory_iterator DI = directory_iterator(DirPath, EC);
- directory_iterator DE;
- for (; !EC && DI != DE; DI = DI.increment(EC)) {
- if (is_regular_file(DI->path()))
- Filenames.push_back(std::string(filename(DI->path())));
- }
- return Filenames;
- }
- std::unique_ptr<ASTConsumer>
- MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- PPConditionalDirectiveRecord *
- PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
- unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
- unsigned ObjCMTOpts = ObjCMTAction;
- // These are companion flags, they do not enable transformations.
- ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty |
- FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty);
- if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
- // If no specific option was given, enable literals+subscripting transforms
- // by default.
- ObjCMTAction |=
- FrontendOptions::ObjCMT_Literals | FrontendOptions::ObjCMT_Subscripting;
- }
- CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
- std::vector<std::string> AllowList =
- getAllowListFilenames(CI.getFrontendOpts().ObjCMTAllowListPath);
- return std::make_unique<ObjCMigrateASTConsumer>(
- CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
- CI.getFileManager(), PPRec, CI.getPreprocessor(),
- /*isOutputFile=*/true, AllowList);
- }
- namespace {
- struct EditEntry {
- Optional<FileEntryRef> File;
- unsigned Offset = 0;
- unsigned RemoveLen = 0;
- std::string Text;
- };
- } // end anonymous namespace
- namespace llvm {
- template<> struct DenseMapInfo<EditEntry> {
- static inline EditEntry getEmptyKey() {
- EditEntry Entry;
- Entry.Offset = unsigned(-1);
- return Entry;
- }
- static inline EditEntry getTombstoneKey() {
- EditEntry Entry;
- Entry.Offset = unsigned(-2);
- return Entry;
- }
- static unsigned getHashValue(const EditEntry& Val) {
- return (unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
- Val.Text);
- }
- static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) {
- return LHS.File == RHS.File &&
- LHS.Offset == RHS.Offset &&
- LHS.RemoveLen == RHS.RemoveLen &&
- LHS.Text == RHS.Text;
- }
- };
- } // end namespace llvm
- namespace {
- class RemapFileParser {
- FileManager &FileMgr;
- public:
- RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { }
- bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) {
- using namespace llvm::yaml;
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
- llvm::MemoryBuffer::getFile(File);
- if (!FileBufOrErr)
- return true;
- llvm::SourceMgr SM;
- Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM);
- document_iterator I = YAMLStream.begin();
- if (I == YAMLStream.end())
- return true;
- Node *Root = I->getRoot();
- if (!Root)
- return true;
- SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
- if (!SeqNode)
- return true;
- for (SequenceNode::iterator
- AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
- MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
- if (!MapNode)
- continue;
- parseEdit(MapNode, Entries);
- }
- return false;
- }
- private:
- void parseEdit(llvm::yaml::MappingNode *Node,
- SmallVectorImpl<EditEntry> &Entries) {
- using namespace llvm::yaml;
- EditEntry Entry;
- bool Ignore = false;
- for (MappingNode::iterator
- KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) {
- ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
- if (!KeyString)
- continue;
- SmallString<10> KeyStorage;
- StringRef Key = KeyString->getValue(KeyStorage);
- ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
- if (!ValueString)
- continue;
- SmallString<64> ValueStorage;
- StringRef Val = ValueString->getValue(ValueStorage);
- if (Key == "file") {
- if (auto File = FileMgr.getOptionalFileRef(Val))
- Entry.File = File;
- else
- Ignore = true;
- } else if (Key == "offset") {
- if (Val.getAsInteger(10, Entry.Offset))
- Ignore = true;
- } else if (Key == "remove") {
- if (Val.getAsInteger(10, Entry.RemoveLen))
- Ignore = true;
- } else if (Key == "text") {
- Entry.Text = std::string(Val);
- }
- }
- if (!Ignore)
- Entries.push_back(Entry);
- }
- };
- } // end anonymous namespace
- static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
- Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
- << Err.str();
- return true;
- }
- static std::string applyEditsToTemp(FileEntryRef FE,
- ArrayRef<EditEntry> Edits,
- FileManager &FileMgr,
- DiagnosticsEngine &Diag) {
- using namespace llvm::sys;
- SourceManager SM(Diag, FileMgr);
- FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
- LangOptions LangOpts;
- edit::EditedSource Editor(SM, LangOpts);
- for (ArrayRef<EditEntry>::iterator
- I = Edits.begin(), E = Edits.end(); I != E; ++I) {
- const EditEntry &Entry = *I;
- assert(Entry.File == FE);
- SourceLocation Loc =
- SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
- CharSourceRange Range;
- if (Entry.RemoveLen != 0) {
- Range = CharSourceRange::getCharRange(Loc,
- Loc.getLocWithOffset(Entry.RemoveLen));
- }
- edit::Commit commit(Editor);
- if (Range.isInvalid()) {
- commit.insert(Loc, Entry.Text);
- } else if (Entry.Text.empty()) {
- commit.remove(Range);
- } else {
- commit.replace(Range, Entry.Text);
- }
- Editor.commit(commit);
- }
- Rewriter rewriter(SM, LangOpts);
- RewritesReceiver Rec(rewriter);
- Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
- const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
- SmallString<512> NewText;
- llvm::raw_svector_ostream OS(NewText);
- Buf->write(OS);
- SmallString<64> TempPath;
- int FD;
- if (fs::createTemporaryFile(path::filename(FE.getName()),
- path::extension(FE.getName()).drop_front(), FD,
- TempPath)) {
- reportDiag("Could not create file: " + TempPath.str(), Diag);
- return std::string();
- }
- llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true);
- TmpOut.write(NewText.data(), NewText.size());
- TmpOut.close();
- return std::string(TempPath.str());
- }
- bool arcmt::getFileRemappingsFromFileList(
- std::vector<std::pair<std::string,std::string> > &remap,
- ArrayRef<StringRef> remapFiles,
- DiagnosticConsumer *DiagClient) {
- bool hasErrorOccurred = false;
- FileSystemOptions FSOpts;
- FileManager FileMgr(FSOpts);
- RemapFileParser Parser(FileMgr);
- IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, new DiagnosticOptions,
- DiagClient, /*ShouldOwnClient=*/false));
- typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
- FileEditEntriesTy;
- FileEditEntriesTy FileEditEntries;
- llvm::DenseSet<EditEntry> EntriesSet;
- for (ArrayRef<StringRef>::iterator
- I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
- SmallVector<EditEntry, 16> Entries;
- if (Parser.parse(*I, Entries))
- continue;
- for (SmallVectorImpl<EditEntry>::iterator
- EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
- EditEntry &Entry = *EI;
- if (!Entry.File)
- continue;
- std::pair<llvm::DenseSet<EditEntry>::iterator, bool>
- Insert = EntriesSet.insert(Entry);
- if (!Insert.second)
- continue;
- FileEditEntries[*Entry.File].push_back(Entry);
- }
- }
- for (FileEditEntriesTy::iterator
- I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
- std::string TempFile = applyEditsToTemp(I->first, I->second,
- FileMgr, *Diags);
- if (TempFile.empty()) {
- hasErrorOccurred = true;
- continue;
- }
- remap.emplace_back(std::string(I->first.getName()), TempFile);
- }
- return hasErrorOccurred;
- }
|