forked from OSchip/llvm-project
ObjectiveC migrator: Provide ARC annotations for
CF methods too. llvm-svn: 189041
This commit is contained in:
parent
179b1f8cf2
commit
926fafb888
|
@ -57,8 +57,13 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
|
|||
bool migrateAddFunctionAnnotation(ASTContext &Ctx,
|
||||
const FunctionDecl *FuncDecl);
|
||||
|
||||
void migrateObjCMethodDeclAnnotation(ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl);
|
||||
void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
|
||||
|
||||
bool migrateAddMethodAnnotation(ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl);
|
||||
|
||||
void migrateMethodForCFAnnotation(ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl);
|
||||
public:
|
||||
std::string MigrateDir;
|
||||
bool MigrateLiterals;
|
||||
|
@ -73,7 +78,7 @@ public:
|
|||
Preprocessor &PP;
|
||||
bool IsOutputFile;
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
|
||||
llvm::SmallVector<const FunctionDecl *, 8> CFFunctionIBCandidates;
|
||||
llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
|
||||
|
||||
ObjCMigrateASTConsumer(StringRef migrateDir,
|
||||
bool migrateLiterals,
|
||||
|
@ -794,15 +799,17 @@ AuditedType (QualType AT, bool &IsPoniter) {
|
|||
}
|
||||
|
||||
void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
|
||||
if (CFFunctionIBCandidates.empty())
|
||||
return;
|
||||
if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
|
||||
CFFunctionIBCandidates.clear();
|
||||
FileId = 0;
|
||||
return;
|
||||
}
|
||||
// Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
|
||||
const FunctionDecl *FirstFD = CFFunctionIBCandidates[0];
|
||||
const FunctionDecl *LastFD =
|
||||
CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
|
||||
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->getLocStart(), PragmaString);
|
||||
|
@ -810,11 +817,15 @@ void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
|
|||
SourceLocation EndLoc = LastFD->getLocEnd();
|
||||
// get location just past end of function location.
|
||||
EndLoc = PP.getLocForEndOfToken(EndLoc);
|
||||
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();
|
||||
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 = 0;
|
||||
|
@ -838,7 +849,7 @@ void ObjCMigrateASTConsumer::migrateCFFunctions(
|
|||
if (!FileId)
|
||||
FileId = PP.getSourceManager().getFileID(FuncDecl->getLocation()).getHashValue();
|
||||
}
|
||||
else if (!CFFunctionIBCandidates.empty())
|
||||
else
|
||||
AnnotateImplicitBridging(Ctx);
|
||||
}
|
||||
|
||||
|
@ -912,14 +923,109 @@ bool ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
|
|||
return HasAtLeastOnePointer;
|
||||
}
|
||||
|
||||
void ObjCMigrateASTConsumer::migrateObjCMethodDeclAnnotation(
|
||||
void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
|
||||
ObjCContainerDecl *CDecl) {
|
||||
if (!isa<ObjCInterfaceDecl>(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);
|
||||
migrateMethodForCFAnnotation(Ctx, Method);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjCMigrateASTConsumer::migrateMethodForCFAnnotation(
|
||||
ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl) {
|
||||
if (MethodDecl->hasAttr<CFAuditedTransferAttr>() ||
|
||||
MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
|
||||
MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
|
||||
MethodDecl->hasBody())
|
||||
if (MethodDecl->hasAttr<CFAuditedTransferAttr>()) {
|
||||
assert(CFFunctionIBCandidates.empty() &&
|
||||
"Cannot have audited method inside user "
|
||||
"provided CF_IMPLICIT_BRIDGING_ENABLE");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method must be annotated first.
|
||||
bool Audited = migrateAddMethodAnnotation(Ctx, MethodDecl);
|
||||
if (Audited) {
|
||||
CFFunctionIBCandidates.push_back(MethodDecl);
|
||||
if (!FileId)
|
||||
FileId = PP.getSourceManager().getFileID(MethodDecl->getLocation()).getHashValue();
|
||||
}
|
||||
else
|
||||
AnnotateImplicitBridging(Ctx);
|
||||
}
|
||||
|
||||
bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation(ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl) {
|
||||
if (MethodDecl->hasBody())
|
||||
return false;
|
||||
|
||||
CallEffects CE = CallEffects::getEffect(MethodDecl);
|
||||
bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
|
||||
MethodDecl->getAttr<CFReturnsNotRetainedAttr>());
|
||||
|
||||
// Trivial case of when funciton is annotated and has no argument.
|
||||
if (MethodIsReturnAnnotated &&
|
||||
(MethodDecl->param_begin() == MethodDecl->param_end()))
|
||||
return false;
|
||||
|
||||
bool HasAtLeastOnePointer = MethodIsReturnAnnotated;
|
||||
if (!MethodIsReturnAnnotated) {
|
||||
RetEffect Ret = CE.getReturnValue();
|
||||
const char *AnnotationString = 0;
|
||||
if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
|
||||
if (Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
|
||||
AnnotationString = " CF_RETURNS_RETAINED";
|
||||
}
|
||||
else if (Ret.getObjKind() == RetEffect::CF && !Ret.isOwned()) {
|
||||
if (Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
|
||||
AnnotationString = " CF_RETURNS_NOT_RETAINED";
|
||||
}
|
||||
if (AnnotationString) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
|
||||
Editor->commit(commit);
|
||||
HasAtLeastOnePointer = true;
|
||||
}
|
||||
else if (!AuditedType(MethodDecl->getResultType(), HasAtLeastOnePointer))
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point result type is either annotated or audited.
|
||||
// Now, how about argument types.
|
||||
llvm::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 /*CFConsumed annotated*/ ||
|
||||
AE == IncRef) {
|
||||
if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
|
||||
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
|
||||
Editor->commit(commit);
|
||||
HasAtLeastOnePointer = true;
|
||||
}
|
||||
// When AE == IncRef, there is no attribute to annotate with.
|
||||
// It is assumed that compiler will extract the info. from function
|
||||
// API name.
|
||||
HasAtLeastOnePointer = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType AT = pd->getType();
|
||||
bool IsPointer;
|
||||
if (!AuditedType(AT, IsPointer))
|
||||
return false;
|
||||
else if (IsPointer)
|
||||
HasAtLeastOnePointer = true;
|
||||
}
|
||||
return HasAtLeastOnePointer;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -969,15 +1075,15 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
|
|||
}
|
||||
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
|
||||
migrateCFFunctions(Ctx, FD);
|
||||
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*D))
|
||||
migrateObjCMethodDeclAnnotation(Ctx, MD);
|
||||
|
||||
// migrate methods which can have instancetype as their result type.
|
||||
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
|
||||
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
|
||||
// migrate methods which can have instancetype as their result type.
|
||||
migrateInstanceType(Ctx, CDecl);
|
||||
// annotate methods with CF annotations.
|
||||
migrateARCSafeAnnotation(Ctx, CDecl);
|
||||
}
|
||||
}
|
||||
if (!CFFunctionIBCandidates.empty())
|
||||
AnnotateImplicitBridging(Ctx);
|
||||
AnnotateImplicitBridging(Ctx);
|
||||
}
|
||||
|
||||
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
|
||||
|
|
|
@ -197,7 +197,13 @@ typedef double NSTimeInterval;
|
|||
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
|
||||
- (NSUInteger)length;
|
||||
- (NSString *)stringByAppendingString:(NSString *)aString;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
- ( const char *)UTF8String;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
|
||||
+ (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString;
|
||||
@end @class NSString, NSURL, NSError;
|
||||
|
@ -292,9 +298,9 @@ typedef const struct __DADissenter * DADissenterRef;
|
|||
extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ) CF_RETURNS_RETAINED;
|
||||
@interface CIContext: NSObject {
|
||||
}
|
||||
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
|
||||
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
|
||||
- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
|
||||
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r CF_RETURNS_RETAINED;
|
||||
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs CF_RETURNS_RETAINED;
|
||||
- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d CF_RETURNS_RETAINED;
|
||||
@end extern NSString* const QCRendererEventKey;
|
||||
@protocol QCCompositionRenderer - (NSDictionary*) attributes;
|
||||
@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
|
||||
|
@ -819,8 +825,14 @@ void rdar_6866843() {
|
|||
typedef CFTypeRef OtherRef;
|
||||
|
||||
@interface RDar6877235 : NSObject {}
|
||||
- (CFTypeRef)_copyCFTypeRef;
|
||||
- (OtherRef)_copyOtherRef;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
- (CFTypeRef)_copyCFTypeRef CF_RETURNS_RETAINED;
|
||||
- (OtherRef)_copyOtherRef CF_RETURNS_RETAINED;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
@end
|
||||
|
||||
@implementation RDar6877235
|
||||
|
@ -954,7 +966,13 @@ static void PR4230_new(void)
|
|||
typedef struct s6893565* TD6893565;
|
||||
|
||||
@interface RDar6893565 {}
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
-(TD6893565)newThing;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
@end
|
||||
|
||||
@implementation RDar6893565
|
||||
|
@ -1373,7 +1391,13 @@ typedef NSString* MyStringTy;
|
|||
- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
|
||||
- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
|
||||
+ (void) consume:(id) NS_CONSUMED x;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
+ (void) consume2:(id) CF_CONSUMED x;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
@end
|
||||
|
||||
static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
|
||||
|
@ -1448,9 +1472,21 @@ void testattr4() {
|
|||
- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
|
||||
- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
|
||||
- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
|
||||
- (CFDateRef) newCFRetainedAsCFNoAttr;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
- (NSDate*) alsoReturnsRetained;
|
||||
- (CFDateRef) alsoReturnsRetainedAsCF;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_ENABLED
|
||||
|
||||
- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED;
|
||||
|
||||
CF_IMPLICIT_BRIDGING_DISABLED
|
||||
|
||||
- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
|
||||
@end
|
||||
|
||||
|
|
Loading…
Reference in New Issue