diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp | 286 |
1 files changed, 212 insertions, 74 deletions
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp index 1a2055e..52c424c 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp @@ -29,6 +29,7 @@ #include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.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" @@ -81,6 +82,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer { void inferDesignatedInitializers(ASTContext &Ctx, const ObjCImplementationDecl *ImplD); + + bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc); public: std::string MigrateDir; @@ -95,10 +98,11 @@ public: const PPConditionalDirectiveRecord *PPRec; Preprocessor &PP; bool IsOutputFile; + bool FoundationIncluded; llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls; llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; - llvm::StringMap<char> WhiteListFilenames; - + llvm::StringSet<> WhiteListFilenames; + ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions, FileRemapper &remapper, @@ -111,12 +115,12 @@ public: ASTMigrateActions(astMigrateActions), NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr), Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), - IsOutputFile(isOutputFile) { + IsOutputFile(isOutputFile), + FoundationIncluded(false){ - for (ArrayRef<std::string>::iterator - I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) { - WhiteListFilenames.GetOrCreateValue(*I); - } + // FIXME: StringSet should have insert(iter, iter) to use here. + for (const std::string &Val : WhiteList) + WhiteListFilenames.insert(Val); } protected: @@ -185,23 +189,17 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, MigrateDir = "."; // user current directory if none is given. } -ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { +std::unique_ptr<ASTConsumer> +ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); - CompInst->getPreprocessor().addPPCallbacks(PPRec); - ASTConsumer * - WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); - ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, - ObjCMigAction, - Remapper, - CompInst->getFileManager(), - PPRec, - CompInst->getPreprocessor(), - false, - ArrayRef<std::string>()); - ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; - return new MultiplexConsumer(Consumers); + 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(llvm::make_unique<ObjCMigrateASTConsumer>( + MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec, + CompInst->getPreprocessor(), false, None)); + return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { @@ -213,6 +211,110 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { } namespace { + // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp + bool subscriptOperatorNeedsParens(const Expr *FullExpr) { + const Expr* Expr = FullExpr->IgnoreImpCasts(); + if (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)) + return false; + + return true; + } + + /// \brief - 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; + const ObjCMethodDecl *Method = Msg->getMethodDecl(); + if (!Method) + return false; + if (!Method->isPropertyAccessor()) + return false; + + const ObjCInterfaceDecl *IFace = + NS.getASTContext().getObjContainingInterface(Method); + if (!IFace) + 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->getLocEnd(); + 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->getLocStart(), "("); + 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->getLocEnd(); + BegLoc = PP.getLocForEndOfToken(BegLoc); + SourceLocation EndLoc = RHS->getLocStart(); + EndLoc = EndLoc.getLocWithOffset(-1); + 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; @@ -237,6 +339,13 @@ public: 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; } @@ -590,18 +699,32 @@ static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, 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, - bool IsNSIntegerType, + StringRef NSIntegerName, bool NSOptions) { std::string ClassString; - if (NSOptions) - ClassString = "typedef NS_OPTIONS(NSUInteger, "; - else - ClassString = - IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " - : "typedef NS_ENUM(NSUInteger, "; + if (NSOptions) { + ClassString = "typedef NS_OPTIONS("; + ClassString += GetUnsignedName(NSIntegerName); + } + else { + ClassString = "typedef NS_ENUM("; + ClassString += NSIntegerName; + } + ClassString += ", "; ClassString += TypedefDcl->getIdentifier()->getName(); ClassString += ')'; @@ -640,18 +763,31 @@ static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, return false; } -static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl, +static void rewriteToNSMacroDecl(ASTContext &Ctx, + const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType) { - std::string ClassString = - IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, "; + QualType EnumUnderlyingT = EnumDcl->getPromotionType(); + assert(!EnumUnderlyingT.isNull() + && "rewriteToNSMacroDecl - underlying enum type is null"); + + PrintingPolicy Policy(Ctx.getPrintingPolicy()); + std::string TypeString = EnumUnderlyingT.getAsString(Policy); + std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS("; + ClassString += TypeString; + ClassString += ", "; + ClassString += TypedefDcl->getIdentifier()->getName(); ClassString += ')'; SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); commit.replace(R, ClassString); - SourceLocation TypedefLoc = TypedefDcl->getLocEnd(); - commit.remove(SourceRange(TypedefLoc, TypedefLoc)); + // This is to remove spaces between '}' and typedef name. + SourceLocation StartTypedefLoc = EnumDcl->getLocEnd(); + StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1); + SourceLocation EndTypedefLoc = TypedefDcl->getLocEnd(); + + commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc)); } static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, @@ -706,11 +842,9 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols); llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols; - for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I = - ObjCProtocolDecls.begin(), - E = ObjCProtocolDecls.end(); I != E; ++I) - if (!ExplicitProtocols.count(*I)) - PotentialImplicitProtocols.push_back(*I); + for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls) + if (!ExplicitProtocols.count(ProtDecl)) + PotentialImplicitProtocols.push_back(ProtDecl); if (PotentialImplicitProtocols.empty()) return; @@ -768,7 +902,7 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl) { if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || - EnumDcl->isDeprecated()) + EnumDcl->isDeprecated() || EnumDcl->getIntegerTypeSourceInfo()) return false; if (!TypedefDcl) { if (NSIntegerTypedefed) { @@ -792,22 +926,17 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, return false; QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); - bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt); - bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt); + StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt); - if (!IsNSIntegerType && !IsNSUIntegerType) { + 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 (NSOptions) { - if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) - return false; - } - else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) + if (!InsertFoundation(Ctx, TypedefDcl->getLocStart())) return false; edit::Commit commit(*Editor); - rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); + rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); Editor->commit(commit); return true; } @@ -817,15 +946,11 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, // We may still use NS_OPTIONS based on what we find in the enumertor list. bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); - // NS_ENUM must be available. - if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) - return false; - // NS_OPTIONS must be available. - if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) + if (!InsertFoundation(Ctx, TypedefDcl->getLocStart())) return false; edit::Commit commit(*Editor); bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, - commit, IsNSIntegerType, NSOptions); + commit, NSIntegerName, NSOptions); Editor->commit(commit); return Res; } @@ -1606,6 +1731,22 @@ void ObjCMigrateASTConsumer::inferDesignatedInitializers( } } +bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx, + SourceLocation Loc) { + if (FoundationIncluded) + return true; + if (Loc.isInvalid()) + return false; + 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 { @@ -1799,12 +1940,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { } if (IsOutputFile) { - std::string Error; - llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None); - if (!Error.empty()) { + std::error_code EC; + llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::F_None); + if (EC) { DiagnosticsEngine &Diags = Ctx.getDiagnostics(); Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) - << Error; + << EC.message(); return; } @@ -1827,11 +1968,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); vecOS.flush(); - llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( - StringRef(newText.data(), newText.size()), file->getName()); + 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(), memBuf); + Remapper.remap(filePath.str(), std::move(memBuf)); } if (IsOutputFile) { @@ -1865,8 +2007,8 @@ static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) { return Filenames; } -ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { +std::unique_ptr<ASTConsumer> +MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction; @@ -1880,17 +2022,13 @@ ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, ObjCMTAction |= FrontendOptions::ObjCMT_Literals | FrontendOptions::ObjCMT_Subscripting; } - CI.getPreprocessor().addPPCallbacks(PPRec); + CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); std::vector<std::string> WhiteList = getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath); - return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, - ObjCMTAction, - Remapper, - CI.getFileManager(), - PPRec, - CI.getPreprocessor(), - /*isOutputFile=*/true, - WhiteList); + return llvm::make_unique<ObjCMigrateASTConsumer>( + CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper, + CI.getFileManager(), PPRec, CI.getPreprocessor(), + /*isOutputFile=*/true, WhiteList); } namespace { @@ -1949,7 +2087,7 @@ public: return true; llvm::SourceMgr SM; - Stream YAMLStream(FileBufOrErr.get().release(), SM); + Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM); document_iterator I = YAMLStream.begin(); if (I == YAMLStream.end()) return true; |