ObjectiveC migrator: Provide ARC annotations for

CF methods too.

llvm-svn: 189041
This commit is contained in:
Fariborz Jahanian 2013-08-22 18:35:27 +00:00
parent 179b1f8cf2
commit 926fafb888
2 changed files with 172 additions and 30 deletions

View File

@ -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());

View File

@ -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