@@ -57,8 +57,13 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
57
57
bool migrateAddFunctionAnnotation (ASTContext &Ctx,
58
58
const FunctionDecl *FuncDecl);
59
59
60
- void migrateObjCMethodDeclAnnotation (ASTContext &Ctx,
61
- const ObjCMethodDecl *MethodDecl);
60
+ void migrateARCSafeAnnotation (ASTContext &Ctx, ObjCContainerDecl *CDecl);
61
+
62
+ bool migrateAddMethodAnnotation (ASTContext &Ctx,
63
+ const ObjCMethodDecl *MethodDecl);
64
+
65
+ void migrateMethodForCFAnnotation (ASTContext &Ctx,
66
+ const ObjCMethodDecl *MethodDecl);
62
67
public:
63
68
std::string MigrateDir;
64
69
bool MigrateLiterals;
@@ -73,7 +78,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
73
78
Preprocessor &PP;
74
79
bool IsOutputFile;
75
80
llvm::SmallPtrSet<ObjCProtocolDecl *, 32 > ObjCProtocolDecls;
76
- llvm::SmallVector<const FunctionDecl *, 8 > CFFunctionIBCandidates;
81
+ llvm::SmallVector<const Decl *, 8 > CFFunctionIBCandidates;
77
82
78
83
ObjCMigrateASTConsumer (StringRef migrateDir,
79
84
bool migrateLiterals,
@@ -794,27 +799,33 @@ AuditedType (QualType AT, bool &IsPoniter) {
794
799
}
795
800
796
801
void ObjCMigrateASTConsumer::AnnotateImplicitBridging (ASTContext &Ctx) {
802
+ if (CFFunctionIBCandidates.empty ())
803
+ return ;
797
804
if (!Ctx.Idents .get (" CF_IMPLICIT_BRIDGING_ENABLED" ).hasMacroDefinition ()) {
798
805
CFFunctionIBCandidates.clear ();
799
806
FileId = 0 ;
800
807
return ;
801
808
}
802
809
// Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
803
- const FunctionDecl *FirstFD = CFFunctionIBCandidates[0 ];
804
- const FunctionDecl *LastFD =
805
- CFFunctionIBCandidates[CFFunctionIBCandidates.size ()-1 ];
810
+ const Decl *FirstFD = CFFunctionIBCandidates[0 ];
811
+ const Decl *LastFD =
812
+ CFFunctionIBCandidates[CFFunctionIBCandidates.size ()-1 ];
806
813
const char *PragmaString = " \n CF_IMPLICIT_BRIDGING_ENABLED\n\n " ;
807
814
edit::Commit commit (*Editor);
808
815
commit.insertBefore (FirstFD->getLocStart (), PragmaString);
809
816
PragmaString = " \n\n CF_IMPLICIT_BRIDGING_DISABLED\n " ;
810
817
SourceLocation EndLoc = LastFD->getLocEnd ();
811
818
// get location just past end of function location.
812
819
EndLoc = PP.getLocForEndOfToken (EndLoc);
813
- Token Tok;
814
- // get locaiton of token that comes after end of function.
815
- bool Failed = PP.getRawToken (EndLoc, Tok, /* IgnoreWhiteSpace=*/ true );
816
- if (!Failed)
817
- EndLoc = Tok.getLocation ();
820
+ if (isa<FunctionDecl>(LastFD)) {
821
+ // For Methods, EndLoc points to the ending semcolon. So,
822
+ // not of these extra work is needed.
823
+ Token Tok;
824
+ // get locaiton of token that comes after end of function.
825
+ bool Failed = PP.getRawToken (EndLoc, Tok, /* IgnoreWhiteSpace=*/ true );
826
+ if (!Failed)
827
+ EndLoc = Tok.getLocation ();
828
+ }
818
829
commit.insertAfterToken (EndLoc, PragmaString);
819
830
Editor->commit (commit);
820
831
FileId = 0 ;
@@ -838,7 +849,7 @@ void ObjCMigrateASTConsumer::migrateCFFunctions(
838
849
if (!FileId)
839
850
FileId = PP.getSourceManager ().getFileID (FuncDecl->getLocation ()).getHashValue ();
840
851
}
841
- else if (!CFFunctionIBCandidates. empty ())
852
+ else
842
853
AnnotateImplicitBridging (Ctx);
843
854
}
844
855
@@ -912,14 +923,109 @@ bool ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
912
923
return HasAtLeastOnePointer;
913
924
}
914
925
915
- void ObjCMigrateASTConsumer::migrateObjCMethodDeclAnnotation (
926
+ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation (ASTContext &Ctx,
927
+ ObjCContainerDecl *CDecl) {
928
+ if (!isa<ObjCInterfaceDecl>(CDecl))
929
+ return ;
930
+
931
+ // migrate methods which can have instancetype as their result type.
932
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin (),
933
+ MEnd = CDecl->meth_end ();
934
+ M != MEnd; ++M) {
935
+ ObjCMethodDecl *Method = (*M);
936
+ migrateMethodForCFAnnotation (Ctx, Method);
937
+ }
938
+ }
939
+
940
+ void ObjCMigrateASTConsumer::migrateMethodForCFAnnotation (
916
941
ASTContext &Ctx,
917
942
const ObjCMethodDecl *MethodDecl) {
918
- if (MethodDecl->hasAttr <CFAuditedTransferAttr>() ||
919
- MethodDecl-> getAttr <CFReturnsRetainedAttr>() ||
920
- MethodDecl-> getAttr <CFReturnsNotRetainedAttr>() ||
921
- MethodDecl-> hasBody ())
943
+ if (MethodDecl->hasAttr <CFAuditedTransferAttr>()) {
944
+ assert (CFFunctionIBCandidates. empty () &&
945
+ " Cannot have audited method inside user "
946
+ " provided CF_IMPLICIT_BRIDGING_ENABLE " );
922
947
return ;
948
+ }
949
+
950
+ // Method must be annotated first.
951
+ bool Audited = migrateAddMethodAnnotation (Ctx, MethodDecl);
952
+ if (Audited) {
953
+ CFFunctionIBCandidates.push_back (MethodDecl);
954
+ if (!FileId)
955
+ FileId = PP.getSourceManager ().getFileID (MethodDecl->getLocation ()).getHashValue ();
956
+ }
957
+ else
958
+ AnnotateImplicitBridging (Ctx);
959
+ }
960
+
961
+ bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation (ASTContext &Ctx,
962
+ const ObjCMethodDecl *MethodDecl) {
963
+ if (MethodDecl->hasBody ())
964
+ return false ;
965
+
966
+ CallEffects CE = CallEffects::getEffect (MethodDecl);
967
+ bool MethodIsReturnAnnotated = (MethodDecl->getAttr <CFReturnsRetainedAttr>() ||
968
+ MethodDecl->getAttr <CFReturnsNotRetainedAttr>());
969
+
970
+ // Trivial case of when funciton is annotated and has no argument.
971
+ if (MethodIsReturnAnnotated &&
972
+ (MethodDecl->param_begin () == MethodDecl->param_end ()))
973
+ return false ;
974
+
975
+ bool HasAtLeastOnePointer = MethodIsReturnAnnotated;
976
+ if (!MethodIsReturnAnnotated) {
977
+ RetEffect Ret = CE.getReturnValue ();
978
+ const char *AnnotationString = 0 ;
979
+ if (Ret.getObjKind () == RetEffect::CF && Ret.isOwned ()) {
980
+ if (Ctx.Idents .get (" CF_RETURNS_RETAINED" ).hasMacroDefinition ())
981
+ AnnotationString = " CF_RETURNS_RETAINED" ;
982
+ }
983
+ else if (Ret.getObjKind () == RetEffect::CF && !Ret.isOwned ()) {
984
+ if (Ctx.Idents .get (" CF_RETURNS_NOT_RETAINED" ).hasMacroDefinition ())
985
+ AnnotationString = " CF_RETURNS_NOT_RETAINED" ;
986
+ }
987
+ if (AnnotationString) {
988
+ edit::Commit commit (*Editor);
989
+ commit.insertBefore (MethodDecl->getLocEnd (), AnnotationString);
990
+ Editor->commit (commit);
991
+ HasAtLeastOnePointer = true ;
992
+ }
993
+ else if (!AuditedType (MethodDecl->getResultType (), HasAtLeastOnePointer))
994
+ return false ;
995
+ }
996
+
997
+ // At this point result type is either annotated or audited.
998
+ // Now, how about argument types.
999
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs ();
1000
+ unsigned i = 0 ;
1001
+ for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin (),
1002
+ pe = MethodDecl->param_end (); pi != pe; ++pi , ++i) {
1003
+ const ParmVarDecl *pd = *pi ;
1004
+ ArgEffect AE = AEArgs[i];
1005
+ if (AE == DecRef /* CFConsumed annotated*/ ||
1006
+ AE == IncRef) {
1007
+ if (AE == DecRef && !pd->getAttr <CFConsumedAttr>() &&
1008
+ Ctx.Idents .get (" CF_CONSUMED" ).hasMacroDefinition ()) {
1009
+ edit::Commit commit (*Editor);
1010
+ commit.insertBefore (pd->getLocation (), " CF_CONSUMED " );
1011
+ Editor->commit (commit);
1012
+ HasAtLeastOnePointer = true ;
1013
+ }
1014
+ // When AE == IncRef, there is no attribute to annotate with.
1015
+ // It is assumed that compiler will extract the info. from function
1016
+ // API name.
1017
+ HasAtLeastOnePointer = true ;
1018
+ continue ;
1019
+ }
1020
+
1021
+ QualType AT = pd->getType ();
1022
+ bool IsPointer;
1023
+ if (!AuditedType (AT, IsPointer))
1024
+ return false ;
1025
+ else if (IsPointer)
1026
+ HasAtLeastOnePointer = true ;
1027
+ }
1028
+ return HasAtLeastOnePointer;
923
1029
}
924
1030
925
1031
namespace {
@@ -969,15 +1075,15 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
969
1075
}
970
1076
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
971
1077
migrateCFFunctions (Ctx, FD);
972
- else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*D))
973
- migrateObjCMethodDeclAnnotation (Ctx, MD);
974
1078
975
- // migrate methods which can have instancetype as their result type.
976
- if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
1079
+ if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1080
+ // migrate methods which can have instancetype as their result type.
977
1081
migrateInstanceType (Ctx, CDecl);
1082
+ // annotate methods with CF annotations.
1083
+ migrateARCSafeAnnotation (Ctx, CDecl);
1084
+ }
978
1085
}
979
- if (!CFFunctionIBCandidates.empty ())
980
- AnnotateImplicitBridging (Ctx);
1086
+ AnnotateImplicitBridging (Ctx);
981
1087
}
982
1088
983
1089
Rewriter rewriter (Ctx.getSourceManager (), Ctx.getLangOpts ());
0 commit comments