aboutsummaryrefslogtreecommitdiff
path: root/lib/ARCMigrate/ObjCMT.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ARCMigrate/ObjCMT.cpp')
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp710
1 files changed, 536 insertions, 174 deletions
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index cac0fb0aed1b..1a2055e9c452 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -8,12 +8,15 @@
//===----------------------------------------------------------------------===//
#include "Transforms.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"
@@ -24,11 +27,11 @@
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
-#include "clang/AST/Attr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
using namespace clang;
using namespace arcmt;
@@ -45,7 +48,6 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void migrateDecl(Decl *D);
void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
- void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl);
void migrateProtocolConformance(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl);
void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
@@ -76,14 +78,18 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void migrateAddMethodAnnotation(ASTContext &Ctx,
const ObjCMethodDecl *MethodDecl);
+
+ void inferDesignatedInitializers(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImplD);
+
public:
std::string MigrateDir;
unsigned ASTMigrateActions;
FileID FileId;
const TypedefDecl *NSIntegerTypedefed;
const TypedefDecl *NSUIntegerTypedefed;
- OwningPtr<NSAPI> NSAPIObj;
- OwningPtr<edit::EditedSource> Editor;
+ std::unique_ptr<NSAPI> NSAPIObj;
+ std::unique_ptr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
const PPConditionalDirectiveRecord *PPRec;
@@ -103,7 +109,7 @@ public:
ArrayRef<std::string> WhiteList)
: MigrateDir(migrateDir),
ASTMigrateActions(astMigrateActions),
- NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
+ NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
IsOutputFile(isOutputFile) {
@@ -114,26 +120,26 @@ public:
}
protected:
- virtual void Initialize(ASTContext &Context) {
+ void Initialize(ASTContext &Context) override {
NSAPIObj.reset(new NSAPI(Context));
Editor.reset(new edit::EditedSource(Context.getSourceManager(),
Context.getLangOpts(),
- PPRec, false));
+ PPRec));
}
- virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
migrateDecl(*I);
return true;
}
- virtual void HandleInterestingDecl(DeclGroupRef DG) {
+ void HandleInterestingDecl(DeclGroupRef DG) override {
// Ignore decls from the PCH.
}
- virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
}
- virtual void HandleTranslationUnit(ASTContext &Ctx);
+ void HandleTranslationUnit(ASTContext &Ctx) override;
bool canModifyFile(StringRef Path) {
if (WhiteListFilenames.empty())
@@ -141,6 +147,30 @@ protected:
return WhiteListFilenames.find(llvm::sys::path::filename(Path))
!= WhiteListFilenames.end();
}
+ bool canModifyFile(const FileEntry *FE) {
+ if (!FE)
+ return false;
+ return canModifyFile(FE->getName());
+ }
+ bool canModifyFile(FileID FID) {
+ if (FID.isInvalid())
+ return false;
+ return canModifyFile(PP.getSourceManager().getFileEntryForID(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);
+ }
};
}
@@ -150,7 +180,7 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
unsigned migrateAction)
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
ObjCMigAction(migrateAction),
- CompInst(0) {
+ CompInst(nullptr) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
}
@@ -223,7 +253,7 @@ public:
class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
ObjCMigrateASTConsumer &Consumer;
- OwningPtr<ParentMap> PMap;
+ std::unique_ptr<ParentMap> PMap;
public:
BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
@@ -294,7 +324,9 @@ void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
bool RetainableObject = ArgType->isObjCRetainableType();
- if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
+ if (RetainableObject &&
+ (propertyLifetime == Qualifiers::OCL_Strong
+ || propertyLifetime == Qualifiers::OCL_None)) {
if (const ObjCObjectPointerType *ObjPtrTy =
ArgType->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
@@ -302,7 +334,7 @@ static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType
IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
return "copy";
else
- return "retain";
+ return "strong";
}
else if (ArgType->isBlockPointerType())
return "copy";
@@ -311,8 +343,8 @@ static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType
// looking into setter's implementation for backing weak ivar.
return "weak";
else if (RetainableObject)
- return ArgType->isBlockPointerType() ? "copy" : "retain";
- return 0;
+ return ArgType->isBlockPointerType() ? "copy" : "strong";
+ return nullptr;
}
static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
@@ -344,23 +376,23 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
PropertyString += PropertyNameString;
}
// Property with no setter may be suggested as a 'readonly' property.
- if (!Setter) {
+ if (!Setter)
append_attr(PropertyString, "readonly", LParenAdded);
- QualType ResType = Context.getCanonicalType(Getter->getResultType());
- if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
- append_attr(PropertyString, MemoryManagementAttr, 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.find("delegate") != StringRef::npos) ||
(PropertyName.find("dataSource") != StringRef::npos)) {
- QualType QT = Getter->getResultType();
+ QualType QT = Getter->getReturnType();
if (!QT->isRealType())
append_attr(PropertyString, "assign", LParenAdded);
- }
- else if (Setter) {
+ } 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))
@@ -368,7 +400,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
}
if (LParenAdded)
PropertyString += ')';
- QualType RT = Getter->getResultType();
+ QualType RT = Getter->getReturnType();
if (!isa<TypedefType>(RT)) {
// strip off any ARC lifetime qualifier.
QualType CanResultTy = Context.getCanonicalType(RT);
@@ -419,21 +451,27 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
// Get location past ';'
EndLoc = EndLoc.getLocWithOffset(1);
SourceLocation BeginOfSetterDclLoc = Setter->getLocStart();
- // FIXME. This assumes that setter decl; is immediately preceeded by eoln.
+ // 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::migrateObjCInterfaceDecl(ASTContext &Ctx,
ObjCContainerDecl *D) {
- if (D->isDeprecated())
+ if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D))
return;
-
- for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+
+ for (auto *Method : D->methods()) {
if (Method->isDeprecated())
continue;
bool PropertyInferred = migrateProperty(Ctx, D, Method);
@@ -448,48 +486,13 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
return;
- for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
- E = D->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : D->properties()) {
if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
!Prop->isDeprecated())
migratePropertyNsReturnsInnerPointer(Ctx, Prop);
}
}
-void ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx,
- ObjCCategoryDecl *CatDecl) {
- StringRef Name = CatDecl->getName();
- if (!Name.endswith("Deprecated"))
- return;
-
- if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition())
- return;
-
- ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl);
-
- for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
- if (Method->isDeprecated() || Method->isImplicit())
- continue;
- // Annotate with DEPRECATED
- edit::Commit commit(*Editor);
- commit.insertBefore(Method->getLocEnd(), " DEPRECATED");
- Editor->commit(commit);
- }
- for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
- E = D->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->isDeprecated())
- continue;
- // Annotate with DEPRECATED
- edit::Commit commit(*Editor);
- commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED");
- Editor->commit(commit);
- }
-}
-
static bool
ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl,
@@ -500,9 +503,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
// in class interface.
bool HasAtleastOneRequiredProperty = false;
if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Property = *P;
+ for (const auto *Property : PDecl->properties()) {
if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
HasAtleastOneRequiredProperty = true;
@@ -532,9 +533,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
if (PDecl->meth_begin() == PDecl->meth_end())
return HasAtleastOneRequiredProperty;
- for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
- MEnd = PDecl->meth_end(); M != MEnd; ++M) {
- ObjCMethodDecl *MD = (*M);
+ for (const auto *MD : PDecl->methods()) {
if (MD->isImplicit())
continue;
if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
@@ -632,7 +631,7 @@ static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
/*IsDecl*/true);
if (!EndOfEnumDclLoc.isInvalid()) {
SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
- // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
+ // 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));
@@ -660,9 +659,7 @@ static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
bool PowerOfTwo = true;
bool AllHexdecimalEnumerator = true;
uint64_t MaxPowerOfTwoVal = 0;
- for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
- EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
- EnumConstantDecl *Enumerator = (*EI);
+ for (auto Enumerator : EnumDcl->enumerators()) {
const Expr *InitExpr = Enumerator->getInitExpr();
if (!InitExpr) {
PowerOfTwo = false;
@@ -749,6 +746,8 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
if (!DropIt)
MinimalConformingProtocols.push_back(TargetPDecl);
}
+ if (MinimalConformingProtocols.empty())
+ return;
edit::Commit commit(*Editor);
rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
*NSAPIObj, commit);
@@ -774,11 +773,11 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
if (!TypedefDcl) {
if (NSIntegerTypedefed) {
TypedefDcl = NSIntegerTypedefed;
- NSIntegerTypedefed = 0;
+ NSIntegerTypedefed = nullptr;
}
else if (NSUIntegerTypedefed) {
TypedefDcl = NSUIntegerTypedefed;
- NSUIntegerTypedefed = 0;
+ NSUIntegerTypedefed = nullptr;
}
else
return false;
@@ -831,11 +830,15 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
return Res;
}
-static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
+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->getResultTypeSourceInfo()) {
+ if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc();
R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
ClassString = "instancetype";
@@ -855,7 +858,7 @@ static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
ObjCInterfaceDecl *IDecl = OM->getClassInterface();
SourceRange R;
std::string ClassString;
- if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc();
R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
ClassString = IDecl->getName();
@@ -893,14 +896,14 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
return;
case OIT_Init:
- if (OM->getResultType()->isObjCIdType())
- ReplaceWithInstancetype(*this, OM);
+ if (OM->getReturnType()->isObjCIdType())
+ ReplaceWithInstancetype(Ctx, *this, OM);
return;
case OIT_ReturnsSelf:
migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
return;
}
- if (!OM->getResultType()->isObjCIdType())
+ if (!OM->getReturnType()->isObjCIdType())
return;
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
@@ -915,7 +918,7 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
migrateFactoryMethod(Ctx, CDecl, OM);
return;
}
- ReplaceWithInstancetype(*this, OM);
+ ReplaceWithInstancetype(Ctx, *this, OM);
}
static bool TypeIsInnerPointer(QualType T) {
@@ -1034,7 +1037,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
Method->param_size() != 0)
return false;
// Is this method candidate to be a getter?
- QualType GRT = Method->getResultType();
+ QualType GRT = Method->getReturnType();
if (GRT->isVoidType())
return false;
@@ -1087,7 +1090,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
return false;
// Is this a valid setter, matching the target getter?
- QualType SRT = SetterMethod->getResultType();
+ QualType SRT = SetterMethod->getReturnType();
if (!SRT->isVoidType())
return false;
const ParmVarDecl *argDecl = *SetterMethod->param_begin();
@@ -1109,7 +1112,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
// 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, 0 /*SetterMethod*/, *NSAPIObj, commit,
+ rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
LengthOfPrefix,
(ASTMigrateActions &
FrontendOptions::ObjCMT_AtomicProperty) != 0,
@@ -1128,8 +1131,8 @@ void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
!OM->isInstanceMethod() ||
OM->hasAttr<ObjCReturnsInnerPointerAttr>())
return;
-
- QualType RT = OM->getResultType();
+
+ QualType RT = OM->getReturnType();
if (!TypeIsInnerPointer(RT) ||
!Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
return;
@@ -1153,14 +1156,11 @@ void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ct
void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
ObjCContainerDecl *CDecl) {
- if (CDecl->isDeprecated())
+ if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
return;
// migrate methods which can have instancetype as their result type.
- for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
- MEnd = CDecl->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+ for (auto *Method : CDecl->methods()) {
if (Method->isDeprecated())
continue;
migrateMethodInstanceType(Ctx, CDecl, Method);
@@ -1172,8 +1172,8 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
ObjCMethodDecl *OM,
ObjCInstanceTypeFamily OIT_Family) {
if (OM->isInstanceMethod() ||
- OM->getResultType() == Ctx.getObjCInstanceType() ||
- !OM->getResultType()->isObjCIdType())
+ OM->getReturnType() == Ctx.getObjCInstanceType() ||
+ !OM->getReturnType()->isObjCIdType())
return;
// Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
@@ -1228,7 +1228,7 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
if (OIT_Family == OIT_ReturnsSelf)
ReplaceWithClasstype(*this, OM);
else
- ReplaceWithInstancetype(*this, OM);
+ ReplaceWithInstancetype(Ctx, *this, OM);
}
static bool IsVoidStarType(QualType Ty) {
@@ -1338,7 +1338,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
// Annotate function.
if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue();
- const char *AnnotationString = 0;
+ const char *AnnotationString = nullptr;
if (Ret.getObjKind() == RetEffect::CF) {
if (Ret.isOwned() &&
Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
@@ -1359,19 +1359,19 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit);
}
}
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
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 = AEArgs[i];
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
Editor->commit(commit);
}
- else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
+ else if (AE == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() &&
Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
@@ -1389,11 +1389,11 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
return CF_BRIDGING_NONE;
CallEffects CE = CallEffects::getEffect(FuncDecl);
- bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
- FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
+ bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
+ FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
// Trivial case of when funciton is annotated and has no argument.
if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
@@ -1405,13 +1405,13 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
if (Ret.getObjKind() == RetEffect::CF &&
(Ret.isOwned() || Ret.notOwned()))
ReturnCFAudited = true;
- else if (!AuditedType(FuncDecl->getResultType()))
+ else if (!AuditedType(FuncDecl->getReturnType()))
return CF_BRIDGING_NONE;
}
// At this point result type is audited for potential inclusion.
// Now, how about argument types.
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0;
bool ArgCFAudited = false;
for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
@@ -1419,7 +1419,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i];
if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>())
ArgCFAudited = true;
else if (AE == IncRef)
ArgCFAudited = true;
@@ -1444,12 +1444,8 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
return;
// migrate methods which can have instancetype as their result type.
- for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
- MEnd = CDecl->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+ for (const auto *Method : CDecl->methods())
migrateCFAnnotation(Ctx, Method);
- }
}
void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
@@ -1459,7 +1455,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
// Annotate function.
if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue();
- const char *AnnotationString = 0;
+ const char *AnnotationString = nullptr;
if (Ret.getObjKind() == RetEffect::CF) {
if (Ret.isOwned() &&
Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
@@ -1492,13 +1488,13 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit);
}
}
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
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 = AEArgs[i];
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
@@ -1514,14 +1510,14 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
return;
CallEffects CE = CallEffects::getEffect(MethodDecl);
- bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
- MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
+ bool MethodIsReturnAnnotated = (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
+ MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
if (CE.getReceiver() == DecRefMsg &&
- !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
+ !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
MethodDecl->getMethodFamily() != OMF_init &&
MethodDecl->getMethodFamily() != OMF_release &&
Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
@@ -1542,20 +1538,19 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
(Ret.isOwned() || Ret.notOwned())) {
AddCFAnnotations(Ctx, CE, MethodDecl, false);
return;
- }
- else if (!AuditedType(MethodDecl->getResultType()))
+ } else if (!AuditedType(MethodDecl->getReturnType()))
return;
}
// At this point result type is either annotated or audited.
// Now, how about argument types.
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
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 = AEArgs[i];
- if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
+ if ((AE == DecRef && !pd->hasAttr<CFConsumedAttr>()) || AE == IncRef ||
!AuditedType(pd->getType())) {
AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
return;
@@ -1565,6 +1560,53 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
}
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;
+ }
+};
+} // 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 (!Ctx.Idents.get("NS_DESIGNATED_INITIALIZER").hasMacroDefinition())
+ 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->getLocEnd(), " NS_DESIGNATED_INITIALIZER");
+ Editor->commit(commit);
+ }
+ }
+}
+
+namespace {
class RewritesReceiver : public edit::EditsReceiver {
Rewriter &Rewrite;
@@ -1572,42 +1614,92 @@ class RewritesReceiver : public edit::EditsReceiver {
public:
RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
- virtual void insert(SourceLocation loc, StringRef text) {
+ void insert(SourceLocation loc, StringRef text) override {
Rewrite.InsertText(loc, text);
}
- virtual void replace(CharSourceRange range, StringRef 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;
-static bool
-IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
- bool Invalid = false;
- const SrcMgr::SLocEntry &SEntry =
- Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
- if (!Invalid && SEntry.isFile()) {
- const SrcMgr::FileInfo &FI = SEntry.getFile();
- if (!FI.hasLineDirectives()) {
- if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
- return true;
- if (FI.getFileCharacteristic() == SrcMgr::C_System) {
- // This file is in a system header directory. Continue with commiting change
- // only if it is a user specified system directory because user put a
- // .system_framework file in the framework directory.
- StringRef Directory(file->getDir()->getName());
- size_t Ix = Directory.rfind(".framework");
- if (Ix == StringRef::npos)
- return true;
- std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
- PatchToSystemFramework += ".system_framework";
- if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
- return true;
- }
+public:
+ JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS)
+ : SourceMgr(SM), OS(OS) {
+ OS << "[\n";
+ }
+ ~JSONEditWriter() {
+ 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.isInvalid());
+ 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);
}
- return false;
+
+ 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);
+ }
+};
+
}
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
@@ -1624,22 +1716,25 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
}
if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
- migrateObjCInterfaceDecl(Ctx, CDecl);
+ if (canModify(CDecl))
+ migrateObjCInterfaceDecl(Ctx, CDecl);
if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
- migrateObjCInterfaceDecl(Ctx, CatDecl);
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
- migrateDeprecatedAnnotation(Ctx, CatDecl);
+ if (canModify(CatDecl))
+ migrateObjCInterfaceDecl(Ctx, CatDecl);
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
- ObjCProtocolDecls.insert(PDecl);
+ ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
else if (const ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(*D)) {
- if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
+ 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);
@@ -1647,11 +1742,13 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
D++;
}
else
- migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
+ 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;
@@ -1673,23 +1770,49 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
CacheObjCNSIntegerTypedefed(TD);
}
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ 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)
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) &&
+ CanModify)
migrateAllMethodInstaceType(Ctx, CDecl);
// annotate methods with CF annotations.
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ 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::string Error;
+ llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None);
+ if (!Error.empty()) {
+ DiagnosticsEngine &Diags = Ctx.getDiagnostics();
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << Error;
+ return;
+ }
+
+ JSONEditWriter Writer(Ctx.getSourceManager(), OS);
+ Editor->applyRewrites(Writer);
+ return;
+ }
+
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
RewritesReceiver Rec(rewriter);
Editor->applyRewrites(Rec);
@@ -1700,10 +1823,6 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
- if (IsReallyASystemHeader(Ctx, file, FID))
- continue;
- if (!canModifyFile(file->getName()))
- continue;
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
@@ -1734,8 +1853,8 @@ static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
std::vector<std::string> Filenames;
if (DirPath.empty() || !is_directory(DirPath))
return Filenames;
-
- llvm::error_code EC;
+
+ std::error_code EC;
directory_iterator DI = directory_iterator(DirPath, EC);
directory_iterator DE;
for (; !EC && DI != DE; DI = DI.increment(EC)) {
@@ -1773,3 +1892,246 @@ ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
/*isOutputFile=*/true,
WhiteList);
}
+
+namespace {
+struct EditEntry {
+ const FileEntry *File;
+ unsigned Offset;
+ unsigned RemoveLen;
+ std::string Text;
+
+ EditEntry() : File(), Offset(), RemoveLen() {}
+};
+}
+
+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) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(Val.File);
+ ID.AddInteger(Val.Offset);
+ ID.AddInteger(Val.RemoveLen);
+ ID.AddString(Val.Text);
+ return ID.ComputeHash();
+ }
+ 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;
+ }
+};
+}
+
+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().release(), 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") {
+ const FileEntry *FE = FileMgr.getFile(Val);
+ if (!FE)
+ Ignore = true;
+ Entry.File = FE;
+ } 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 = Val;
+ }
+ }
+
+ if (!Ignore)
+ Entries.push_back(Entry);
+ }
+};
+}
+
+static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
+ Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << Err.str();
+ return true;
+}
+
+static std::string applyEditsToTemp(const FileEntry *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);
+
+ const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
+ SmallString<512> NewText;
+ llvm::raw_svector_ostream OS(NewText);
+ Buf->write(OS);
+ OS.flush();
+
+ SmallString<64> TempPath;
+ int FD;
+ if (fs::createTemporaryFile(path::filename(FE->getName()),
+ path::extension(FE->getName()), 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 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<const FileEntry *, 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.push_back(std::make_pair(I->first->getName(), TempFile));
+ }
+
+ return hasErrorOccurred;
+}