30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/StringSet.h"
32#include "llvm/Support/Path.h"
33#include "llvm/Support/SourceMgr.h"
34#include "llvm/Support/YAMLParser.h"
43 enum CF_BRIDGING_KIND {
46 CF_BRIDGING_MAY_INCLUDE
49 void migrateDecl(
Decl *D);
51 void migrateProtocolConformance(
ASTContext &Ctx,
53 void CacheObjCNSIntegerTypedefed(
const TypedefDecl *TypedefDcl);
74 void AnnotateImplicitBridging(
ASTContext &Ctx);
76 CF_BRIDGING_KIND migrateAddFunctionAnnotation(
ASTContext &Ctx,
81 void migrateAddMethodAnnotation(
ASTContext &Ctx,
84 void inferDesignatedInitializers(
ASTContext &Ctx,
89 std::unique_ptr<RetainSummaryManager> Summaries;
92 std::string MigrateDir;
93 unsigned ASTMigrateActions;
97 std::unique_ptr<NSAPI> NSAPIObj;
98 std::unique_ptr<edit::EditedSource> Editor;
104 bool FoundationIncluded;
107 llvm::StringSet<> AllowListFilenames;
117 ObjCMigrateASTConsumer(StringRef migrateDir,
unsigned astMigrateActions,
122 : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions),
123 NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
124 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
125 IsOutputFile(isOutputFile), FoundationIncluded(
false) {
126 AllowListFilenames.insert(AllowList.begin(), AllowList.end());
131 NSAPIObj.reset(
new NSAPI(Context));
146 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
151 bool canModifyFile(StringRef Path) {
152 if (AllowListFilenames.empty())
154 return AllowListFilenames.contains(llvm::sys::path::filename(Path));
159 return canModifyFile(FE->
getName());
161 bool canModifyFile(
FileID FID) {
167 bool canModify(
const Decl *D) {
171 return canModify(CatImpl->getCategoryDecl());
173 return canModify(Impl->getClassInterface());
175 return canModify(cast<Decl>(MD->getDeclContext()));
178 return canModifyFile(FID);
185 std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
186 unsigned migrateAction)
188 ObjCMigAction(migrateAction), CompInst(nullptr) {
189 if (MigrateDir.empty())
193std::unique_ptr<ASTConsumer>
198 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
200 Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
201 MigrateDir, ObjCMigAction, Remapper, CompInst->
getFileManager(), PPRec,
203 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
218 return !(isa<ArraySubscriptExpr>(
Expr) || isa<CallExpr>(
Expr) ||
219 isa<DeclRefExpr>(
Expr) || isa<CXXNamedCastExpr>(
Expr) ||
220 isa<CXXConstructExpr>(
Expr) || isa<CXXThisExpr>(
Expr) ||
221 isa<CXXTypeidExpr>(
Expr) ||
222 isa<CXXUnresolvedConstructExpr>(
Expr) ||
223 isa<ObjCMessageExpr>(
Expr) || isa<ObjCPropertyRefExpr>(
Expr) ||
224 isa<ObjCProtocolExpr>(
Expr) || isa<MemberExpr>(
Expr) ||
225 isa<ObjCIvarRefExpr>(
Expr) || isa<ParenExpr>(
FullExpr) ||
226 isa<ParenListExpr>(
Expr) || isa<SizeOfPackExpr>(
Expr));
240 if (Receiver->getType()->isObjCBuiltinType())
254 bool ReceiverIsSuper =
268 std::string PropertyDotString;
273 PropertyDotString =
").";
276 PropertyDotString =
".";
277 PropertyDotString += Prop->
getName();
278 commit.
replace(SpaceRange, PropertyDotString);
286 std::string PropertyDotString =
".";
287 PropertyDotString += Prop->
getName();
288 PropertyDotString +=
" =";
290 const Expr *RHS = Args[0];
300 if (colon && colon[0] ==
':')
301 PropertyDotString +=
" ";
312 ObjCMigrateASTConsumer &Consumer;
316 ObjCMigrator(ObjCMigrateASTConsumer &consumer,
ParentMap &PMap)
317 : Consumer(consumer), PMap(PMap) { }
319 bool shouldVisitTemplateInstantiations()
const {
return false; }
320 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
326 Consumer.Editor->commit(commit);
332 Consumer.Editor->commit(commit);
337 rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
339 Consumer.Editor->commit(commit);
349 if (!TraverseStmt(SubStmt))
352 return WalkUpFromObjCMessageExpr(E);
357 ObjCMigrateASTConsumer &Consumer;
358 std::unique_ptr<ParentMap> PMap;
361 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
363 bool shouldVisitTemplateInstantiations()
const {
return false; }
364 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
366 bool TraverseStmt(
Stmt *S) {
368 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
374void ObjCMigrateASTConsumer::migrateDecl(
Decl *D) {
377 if (isa<ObjCMethodDecl>(D))
380 BodyMigrator(*this).TraverseDecl(D);
383static void append_attr(std::string &PropertyString,
const char *attr,
386 PropertyString +=
"(";
390 PropertyString +=
", ";
391 PropertyString +=
attr;
396 const std::string& TypeString,
398 const char *argPtr = TypeString.c_str();
403 PropertyString += *argPtr;
407 PropertyString += *argPtr;
412 PropertyString += (*argPtr);
414 PropertyString += name;
419 PropertyString += *argPtr;
429 if (RetainableObject &&
447 else if (RetainableObject)
455 unsigned LengthOfPrefix,
456 bool Atomic,
bool UseNsIosOnlyMacro,
457 bool AvailabilityArgsMatch) {
459 bool LParenAdded =
false;
460 std::string PropertyString =
"@property ";
461 if (UseNsIosOnlyMacro && NS.
isMacroDefined(
"NS_NONATOMIC_IOSONLY")) {
462 PropertyString +=
"(NS_NONATOMIC_IOSONLY";
465 PropertyString +=
"(nonatomic";
470 StringRef PropertyName(PropertyNameString);
471 if (LengthOfPrefix > 0) {
473 PropertyString +=
"(getter=";
477 PropertyString +=
", getter=";
478 PropertyString += PropertyNameString;
482 append_attr(PropertyString,
"readonly", LParenAdded);
487 if (PropertyName.equals(
"target") || PropertyName.contains(
"delegate") ||
488 PropertyName.contains(
"dataSource")) {
491 append_attr(PropertyString,
"assign", LParenAdded);
492 }
else if (!Setter) {
495 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
500 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
503 PropertyString +=
')';
514 PropertyString +=
" ";
518 std::string TypeString = RT.
getAsString(SubPolicy);
519 if (LengthOfPrefix > 0) {
522 StringRef PropertyNameStringRef(PropertyNameString);
523 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
524 PropertyNameString = std::string(PropertyNameStringRef);
525 bool NoLowering = (
isUppercase(PropertyNameString[0]) &&
526 PropertyNameString.size() > 1 &&
529 PropertyNameString[0] =
toLowercase(PropertyNameString[0]);
534 PropertyNameString.c_str());
536 char LastChar = TypeString[TypeString.size()-1];
537 PropertyString += TypeString;
539 PropertyString +=
' ';
540 PropertyString += PropertyNameString;
548 EndGetterSelectorLoc),
550 if (Setter && AvailabilityArgsMatch) {
564 StringRef Name = CatDecl->getName();
565 return Name.ends_with(
"Deprecated");
570void ObjCMigrateASTConsumer::migrateObjCContainerDecl(
ASTContext &Ctx,
575 for (
auto *Method : D->
methods()) {
578 bool PropertyInferred = migrateProperty(Ctx, D, Method);
582 if (!PropertyInferred ||
585 migrateNsReturnsInnerPointer(Ctx, Method);
593 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
605 bool HasAtleastOneRequiredProperty =
false;
607 for (
const auto *
Property : PDecl->instance_properties()) {
610 HasAtleastOneRequiredProperty =
true;
617 Property->getDeclName().getAsIdentifierInfo(),
621 if ((ClassProperty->getPropertyAttributes() !=
622 Property->getPropertyAttributes()) ||
632 bool HasAtleastOneRequiredMethod =
false;
634 if (PDecl->meth_begin() == PDecl->meth_end())
635 return HasAtleastOneRequiredProperty;
636 for (
const auto *MD : PDecl->methods()) {
637 if (MD->isImplicit())
645 HasAtleastOneRequiredMethod =
true;
656 return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
663 std::string ClassString;
667 if (Protocols.
empty()) {
669 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
670 ClassString += ConformingProtocols[i]->getNameAsString();
678 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
679 ClassString += ConformingProtocols[i]->getNameAsString();
692 StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
693 .Case(
"int8_t",
"uint8_t")
694 .Case(
"int16_t",
"uint16_t")
695 .Case(
"int32_t",
"uint32_t")
696 .Case(
"NSInteger",
"NSUInteger")
697 .Case(
"int64_t",
"uint64_t")
698 .Default(NSIntegerName);
705 StringRef NSIntegerName,
707 std::string ClassString;
709 ClassString =
"typedef NS_OPTIONS(";
713 ClassString =
"typedef NS_ENUM(";
714 ClassString += NSIntegerName;
721 commit.
replace(R, ClassString);
725 if (EndOfEnumDclLoc.
isValid()) {
735 if (EndTypedefDclLoc.
isValid()) {
745 if (EndOfEnumDclLoc.
isValid()) {
760 bool IsNSIntegerType) {
762 assert(!DesignatedEnumType.
isNull()
763 &&
"rewriteToNSMacroDecl - underlying enum type is null");
766 std::string TypeString = DesignatedEnumType.
getAsString(Policy);
767 std::string ClassString = IsNSIntegerType ?
"NS_ENUM(" :
"NS_OPTIONS(";
768 ClassString += TypeString;
778 commit.
replace(R, ClassString);
789 bool PowerOfTwo =
true;
790 bool AllHexdecimalEnumerator =
true;
791 uint64_t MaxPowerOfTwoVal = 0;
793 const Expr *InitExpr = Enumerator->getInitExpr();
796 AllHexdecimalEnumerator =
false;
800 if (
const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
801 if (BO->isShiftOp() || BO->isBitwiseOp())
804 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
805 if (PowerOfTwo && EnumVal) {
806 if (!llvm::isPowerOf2_64(EnumVal))
808 else if (EnumVal > MaxPowerOfTwoVal)
809 MaxPowerOfTwoVal = EnumVal;
811 if (AllHexdecimalEnumerator && EnumVal) {
812 bool FoundHexdecimalEnumerator =
false;
818 FoundHexdecimalEnumerator =
819 (StringLit[0] ==
'0' && (
toLowercase(StringLit[1]) ==
'x'));
821 if (!FoundHexdecimalEnumerator)
822 AllHexdecimalEnumerator =
false;
825 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
828void ObjCMigrateASTConsumer::migrateProtocolConformance(
ASTContext &Ctx,
831 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->
isDeprecated())
840 if (!ExplicitProtocols.count(ProtDecl))
841 PotentialImplicitProtocols.push_back(ProtDecl);
843 if (PotentialImplicitProtocols.empty())
850 for (
unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
852 PotentialImplicitProtocols[i]))
853 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
855 if (ConformingProtocols.empty())
861 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
864 for (
unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
866 if (PDecl == TargetPDecl)
875 MinimalConformingProtocols.push_back(TargetPDecl);
877 if (MinimalConformingProtocols.empty())
882 Editor->commit(commit);
885void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
889 if (NSAPIObj->isObjCNSIntegerType(qt))
890 NSIntegerTypedefed = TypedefDcl;
891 else if (NSAPIObj->isObjCNSUIntegerType(qt))
892 NSUIntegerTypedefed = TypedefDcl;
895bool ObjCMigrateASTConsumer::migrateNSEnumDecl(
ASTContext &Ctx,
902 if (NSIntegerTypedefed) {
903 TypedefDcl = NSIntegerTypedefed;
904 NSIntegerTypedefed =
nullptr;
906 else if (NSUIntegerTypedefed) {
907 TypedefDcl = NSUIntegerTypedefed;
908 NSUIntegerTypedefed =
nullptr;
912 FileID FileIdOfTypedefDcl =
916 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
923 StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
925 if (NSIntegerName.empty()) {
928 if (EnumTy->getDecl() == EnumDcl) {
930 if (!InsertFoundation(Ctx, TypedefDcl->
getBeginLoc()))
934 Editor->commit(commit);
943 if (!InsertFoundation(Ctx, TypedefDcl->
getBeginLoc()))
947 commit, NSIntegerName, NSOptions);
948 Editor->commit(commit);
953 const ObjCMigrateASTConsumer &ASTC,
959 std::string ClassString;
961 TypeLoc TL = TSInfo->getTypeLoc();
963 ClassString =
"instancetype";
968 ClassString +=
" (instancetype)";
971 commit.
replace(R, ClassString);
972 ASTC.Editor->commit(commit);
979 std::string ClassString;
981 TypeLoc TL = TSInfo->getTypeLoc();
983 ClassString = std::string(IDecl->
getName());
990 ClassString += IDecl->
getName(); ClassString +=
"*)";
993 commit.
replace(R, ClassString);
994 ASTC.Editor->commit(commit);
997void ObjCMigrateASTConsumer::migrateMethodInstanceType(
ASTContext &Ctx,
1003 std::string ClassName;
1004 switch (OIT_Family) {
1006 migrateFactoryMethod(Ctx, CDecl, OM);
1009 ClassName =
"NSArray";
1012 ClassName =
"NSDictionary";
1031 IDecl = CatDecl->getClassInterface();
1032 else if (
ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1037 migrateFactoryMethod(Ctx, CDecl, OM);
1054 T = TD->getDecl()->getUnderlyingType();
1059 if (UPointeeT->isRecordType()) {
1078 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
1081 const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
1083 VersionTuple Introduced1 = AA1->getIntroduced();
1084 VersionTuple Deprecated1 = AA1->getDeprecated();
1085 VersionTuple Obsoleted1 = AA1->getObsoleted();
1086 bool IsUnavailable1 = AA1->getUnavailable();
1087 VersionTuple Introduced2 = AA2->getIntroduced();
1088 VersionTuple Deprecated2 = AA2->getDeprecated();
1089 VersionTuple Obsoleted2 = AA2->getObsoleted();
1090 bool IsUnavailable2 = AA2->getUnavailable();
1094 IsUnavailable1 == IsUnavailable2);
1098 bool &AvailabilityArgsMatch) {
1100 for (
unsigned i = 0, e = Attrs1.size(); i != e; i++) {
1102 for (
unsigned j = 0, f = Attrs2.size(); j != f; j++) {
1107 if (AvailabilityArgsMatch)
1127 bool &AvailabilityArgsMatch) {
1132 AvailabilityArgsMatch =
true;
1136 if (
match && (Attrs2.size() > Attrs1.size()))
1145 std::string NameString = Name;
1151bool ObjCMigrateASTConsumer::migrateProperty(
ASTContext &Ctx,
1175 unsigned LengthOfPrefix = 0;
1176 if (!SetterMethod) {
1178 StringRef getterNameString = getterName->
getName();
1179 bool IsPrefix = getterNameString.starts_with(
"is");
1184 if (IsPrefix || getterNameString.starts_with(
"get")) {
1185 LengthOfPrefix = (IsPrefix ? 2 : 3);
1186 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1191 if (CGetterName[0] &&
isUppercase(CGetterName[0])) {
1192 getterName = &Ctx.
Idents.
get(CGetterName);
1205 bool AvailabilityArgsMatch;
1221 (ASTMigrateActions &
1223 (ASTMigrateActions &
1225 AvailabilityArgsMatch);
1226 Editor->commit(commit);
1235 (ASTMigrateActions &
1237 (ASTMigrateActions &
1240 Editor->commit(commit);
1246void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(
ASTContext &Ctx,
1250 OM->
hasAttr<ObjCReturnsInnerPointerAttr>())
1255 !NSAPIObj->isMacroDefined(
"NS_RETURNS_INNER_POINTER"))
1260 Editor->commit(commit);
1263void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(
ASTContext &Ctx,
1268 !NSAPIObj->isMacroDefined(
"NS_RETURNS_INNER_POINTER"))
1271 commit.
insertBefore(
P->getEndLoc(),
" NS_RETURNS_INNER_POINTER ");
1272 Editor->commit(commit);
1275void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(
ASTContext &Ctx,
1281 for (
auto *Method : CDecl->
methods()) {
1284 migrateMethodInstanceType(Ctx, CDecl, Method);
1288void ObjCMigrateASTConsumer::migrateFactoryMethod(
ASTContext &Ctx,
1302 IDecl = CatDecl->getClassInterface();
1303 else if (
ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1309 std::string StringClassName = std::string(IDecl->
getName());
1310 StringRef LoweredClassName(StringClassName);
1311 std::string StringLoweredClassName = LoweredClassName.lower();
1312 LoweredClassName = StringLoweredClassName;
1319 std::string MethodName = std::string(MethodIdName->
getName());
1321 StringRef STRefMethodName(MethodName);
1323 if (STRefMethodName.starts_with(
"standard"))
1324 len = strlen(
"standard");
1325 else if (STRefMethodName.starts_with(
"shared"))
1326 len = strlen(
"shared");
1327 else if (STRefMethodName.starts_with(
"default"))
1328 len = strlen(
"default");
1331 MethodName = std::string(STRefMethodName.substr(len));
1333 std::string MethodNameSubStr = MethodName.substr(0, 3);
1334 StringRef MethodNamePrefix(MethodNameSubStr);
1335 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1336 MethodNamePrefix = StringLoweredMethodNamePrefix;
1337 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1338 if (Ix == StringRef::npos)
1340 std::string ClassNamePostfix = std::string(LoweredClassName.substr(Ix));
1341 StringRef LoweredMethodName(MethodName);
1342 std::string StringLoweredMethodName = LoweredMethodName.lower();
1343 LoweredMethodName = StringLoweredMethodName;
1344 if (!LoweredMethodName.starts_with(ClassNamePostfix))
1380void ObjCMigrateASTConsumer::AnnotateImplicitBridging(
ASTContext &Ctx) {
1381 if (CFFunctionIBCandidates.empty())
1383 if (!NSAPIObj->isMacroDefined(
"CF_IMPLICIT_BRIDGING_ENABLED")) {
1384 CFFunctionIBCandidates.clear();
1389 const Decl *FirstFD = CFFunctionIBCandidates[0];
1390 const Decl *LastFD =
1391 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
1392 const char *PragmaString =
"\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1395 PragmaString =
"\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1399 if (isa<FunctionDecl>(LastFD)) {
1409 Editor->commit(commit);
1411 CFFunctionIBCandidates.clear();
1419 assert(CFFunctionIBCandidates.empty() &&
1420 "Cannot have audited functions/methods inside user "
1421 "provided CF_IMPLICIT_BRIDGING_ENABLE");
1427 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1428 if (AuditKind == CF_BRIDGING_ENABLE) {
1429 CFFunctionIBCandidates.push_back(
Decl);
1433 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1434 if (!CFFunctionIBCandidates.empty()) {
1435 CFFunctionIBCandidates.push_back(
Decl);
1441 AnnotateImplicitBridging(Ctx);
1444 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(
Decl));
1445 AnnotateImplicitBridging(Ctx);
1449void ObjCMigrateASTConsumer::AddCFAnnotations(
ASTContext &Ctx,
1452 bool ResultAnnotated) {
1454 if (!ResultAnnotated) {
1456 const char *AnnotationString =
nullptr;
1457 if (
Ret.getObjKind() == ObjKind::CF) {
1458 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"CF_RETURNS_RETAINED"))
1459 AnnotationString =
" CF_RETURNS_RETAINED";
1460 else if (
Ret.notOwned() &&
1461 NSAPIObj->isMacroDefined(
"CF_RETURNS_NOT_RETAINED"))
1462 AnnotationString =
" CF_RETURNS_NOT_RETAINED";
1464 else if (
Ret.getObjKind() == ObjKind::ObjC) {
1465 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"NS_RETURNS_RETAINED"))
1466 AnnotationString =
" NS_RETURNS_RETAINED";
1469 if (AnnotationString) {
1472 Editor->commit(commit);
1477 pe = FuncDecl->
param_end(); pi != pe; ++pi, ++i) {
1481 !pd->
hasAttr<CFConsumedAttr>() &&
1482 NSAPIObj->isMacroDefined(
"CF_CONSUMED")) {
1485 Editor->commit(commit);
1487 !pd->
hasAttr<NSConsumedAttr>() &&
1488 NSAPIObj->isMacroDefined(
"NS_CONSUMED")) {
1491 Editor->commit(commit);
1496ObjCMigrateASTConsumer::CF_BRIDGING_KIND
1497 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1501 return CF_BRIDGING_NONE;
1504 getSummaryManager(Ctx).getSummary(
AnyCall(FuncDecl));
1505 bool FuncIsReturnAnnotated = (FuncDecl->
hasAttr<CFReturnsRetainedAttr>() ||
1506 FuncDecl->
hasAttr<CFReturnsNotRetainedAttr>() ||
1507 FuncDecl->
hasAttr<NSReturnsRetainedAttr>() ||
1508 FuncDecl->
hasAttr<NSReturnsNotRetainedAttr>() ||
1509 FuncDecl->
hasAttr<NSReturnsAutoreleasedAttr>());
1512 if (FuncIsReturnAnnotated && FuncDecl->
getNumParams() == 0)
1513 return CF_BRIDGING_NONE;
1515 bool ReturnCFAudited =
false;
1516 if (!FuncIsReturnAnnotated) {
1518 if (
Ret.getObjKind() == ObjKind::CF &&
1519 (
Ret.isOwned() ||
Ret.notOwned()))
1520 ReturnCFAudited =
true;
1522 return CF_BRIDGING_NONE;
1527 bool ArgCFAudited =
false;
1529 pe = FuncDecl->
param_end(); pi != pe; ++pi, ++i) {
1535 ArgCFAudited =
true;
1537 ArgCFAudited =
true;
1541 AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
1542 return CF_BRIDGING_NONE;
1546 if (ReturnCFAudited || ArgCFAudited)
1547 return CF_BRIDGING_ENABLE;
1549 return CF_BRIDGING_MAY_INCLUDE;
1552void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(
ASTContext &Ctx,
1554 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->
isDeprecated())
1558 for (
const auto *Method : CDecl->
methods())
1559 migrateCFAnnotation(Ctx, Method);
1562void ObjCMigrateASTConsumer::AddCFAnnotations(
ASTContext &Ctx,
1565 bool ResultAnnotated) {
1567 if (!ResultAnnotated) {
1569 const char *AnnotationString =
nullptr;
1570 if (
Ret.getObjKind() == ObjKind::CF) {
1571 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"CF_RETURNS_RETAINED"))
1572 AnnotationString =
" CF_RETURNS_RETAINED";
1573 else if (
Ret.notOwned() &&
1574 NSAPIObj->isMacroDefined(
"CF_RETURNS_NOT_RETAINED"))
1575 AnnotationString =
" CF_RETURNS_NOT_RETAINED";
1577 else if (
Ret.getObjKind() == ObjKind::ObjC) {
1588 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"NS_RETURNS_RETAINED"))
1589 AnnotationString =
" NS_RETURNS_RETAINED";
1594 if (AnnotationString) {
1597 Editor->commit(commit);
1602 pe = MethodDecl->
param_end(); pi != pe; ++pi, ++i) {
1607 && !pd->
hasAttr<CFConsumedAttr>() &&
1608 NSAPIObj->isMacroDefined(
"CF_CONSUMED")) {
1611 Editor->commit(commit);
1616void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
1623 getSummaryManager(Ctx).getSummary(
AnyCall(MethodDecl));
1625 bool MethodIsReturnAnnotated =
1626 (MethodDecl->
hasAttr<CFReturnsRetainedAttr>() ||
1627 MethodDecl->
hasAttr<CFReturnsNotRetainedAttr>() ||
1628 MethodDecl->
hasAttr<NSReturnsRetainedAttr>() ||
1629 MethodDecl->
hasAttr<NSReturnsNotRetainedAttr>() ||
1630 MethodDecl->
hasAttr<NSReturnsAutoreleasedAttr>());
1633 !MethodDecl->
hasAttr<NSConsumesSelfAttr>() &&
1636 NSAPIObj->isMacroDefined(
"NS_CONSUMES_SELF")) {
1639 Editor->commit(commit);
1643 if (MethodIsReturnAnnotated &&
1647 if (!MethodIsReturnAnnotated) {
1649 if ((
Ret.getObjKind() == ObjKind::CF ||
1650 Ret.getObjKind() == ObjKind::ObjC) &&
1651 (
Ret.isOwned() ||
Ret.notOwned())) {
1652 AddCFAnnotations(Ctx, RS, MethodDecl,
false);
1661 pe = MethodDecl->
param_end(); pi != pe; ++pi, ++i) {
1666 AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
1675 bool shouldVisitTemplateInstantiations()
const {
return false; }
1676 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
1689 return !SuperInitChecker().TraverseStmt(MD->
getBody());
1692void ObjCMigrateASTConsumer::inferDesignatedInitializers(
1699 if (!NSAPIObj->isMacroDefined(
"NS_DESIGNATED_INITIALIZER"))
1703 if (MD->isDeprecated() ||
1704 MD->getMethodFamily() !=
OMF_init ||
1705 MD->isDesignatedInitializerForTheInterface())
1714 Editor->commit(commit);
1719bool ObjCMigrateASTConsumer::InsertFoundation(
ASTContext &Ctx,
1721 if (FoundationIncluded)
1723 if (
Loc.isInvalid())
1725 auto *nsEnumId = &Ctx.
Idents.
get(
"NS_ENUM");
1727 FoundationIncluded =
true;
1732 commit.
insert(
Loc,
"#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
1734 commit.
insert(
Loc,
"#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
1735 Editor->commit(commit);
1736 FoundationIncluded =
true;
1749 Rewrite.InsertText(loc, text);
1758 llvm::raw_ostream &OS;
1762 : SourceMgr(
SM), OS(OS) {
1765 ~JSONEditWriter()
override { OS <<
"]\n"; }
1768 struct EntryWriter {
1770 llvm::raw_ostream &OS;
1773 : SourceMgr(
SM), OS(OS) {
1787 llvm::sys::fs::make_absolute(Path);
1788 OS <<
" \"file\": \"";
1789 OS.write_escaped(Path.str()) <<
"\",\n";
1790 OS <<
" \"offset\": " << Offset <<
",\n";
1794 assert(
Range.isCharRange());
1795 std::pair<FileID, unsigned>
Begin =
1797 std::pair<FileID, unsigned> End =
1799 assert(
Begin.first == End.first);
1800 assert(
Begin.second <= End.second);
1801 unsigned Length = End.second -
Begin.second;
1803 OS <<
" \"remove\": " << Length <<
",\n";
1806 void writeText(StringRef
Text) {
1807 OS <<
" \"text\": \"";
1808 OS.write_escaped(
Text) <<
"\",\n";
1813 EntryWriter Writer(SourceMgr, OS);
1814 Writer.writeLoc(
Loc);
1815 Writer.writeText(
Text);
1819 EntryWriter Writer(SourceMgr, OS);
1820 Writer.writeLoc(
Range.getBegin());
1821 Writer.writeRemove(
Range);
1822 Writer.writeText(
Text);
1826 EntryWriter Writer(SourceMgr, OS);
1827 Writer.writeLoc(
Range.getBegin());
1828 Writer.writeRemove(
Range);
1834void ObjCMigrateASTConsumer::HandleTranslationUnit(
ASTContext &Ctx) {
1842 if (FileId.
isValid() && FileId != FID) {
1844 AnnotateImplicitBridging(Ctx);
1848 if (canModify(CDecl))
1849 migrateObjCContainerDecl(Ctx, CDecl);
1851 if (canModify(CatDecl))
1852 migrateObjCContainerDecl(Ctx, CatDecl);
1856 if (canModify(PDecl))
1857 migrateObjCContainerDecl(Ctx, PDecl);
1860 dyn_cast<ObjCImplementationDecl>(*D)) {
1863 migrateProtocolConformance(Ctx, ImpDecl);
1865 else if (
const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1872 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1873 if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1877 migrateNSEnumDecl(Ctx, ED,
nullptr);
1879 else if (
const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
1887 if (
const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1888 if (canModify(ED)) {
1890 if (
const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
1892 if (migrateNSEnumDecl(Ctx, ED, TDF)) {
1894 CacheObjCNSIntegerTypedefed(TD);
1898 if (migrateNSEnumDecl(Ctx, ED, TD)) {
1904 CacheObjCNSIntegerTypedefed(TD);
1906 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1909 migrateCFAnnotation(Ctx, FD);
1913 bool CanModify = canModify(CDecl);
1917 migrateAllMethodInstaceType(Ctx, CDecl);
1921 migrateARCSafeAnnotation(Ctx, CDecl);
1925 ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
1928 inferDesignatedInitializers(Ctx, ImplD);
1932 AnnotateImplicitBridging(Ctx);
1937 llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
1946 Editor->applyRewrites(Writer);
1951 RewritesReceiver Rec(rewriter);
1952 Editor->applyRewrites(Rec);
1955 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1962 llvm::raw_svector_ostream vecOS(newText);
1964 std::unique_ptr<llvm::MemoryBuffer> memBuf(
1965 llvm::MemoryBuffer::getMemBufferCopy(
1966 StringRef(newText.data(), newText.size()), file->
getName()));
1969 Remapper.
remap(filePath.str(), std::move(memBuf));
1985 using namespace llvm::sys::fs;
1986 using namespace llvm::sys::path;
1988 std::vector<std::string> Filenames;
1989 if (DirPath.empty() || !is_directory(DirPath))
1993 directory_iterator DI = directory_iterator(DirPath, EC);
1994 directory_iterator DE;
1995 for (; !EC && DI != DE; DI = DI.increment(EC)) {
1996 if (is_regular_file(DI->path()))
1997 Filenames.push_back(std::string(filename(DI->path())));
2003std::unique_ptr<ASTConsumer>
2008 unsigned ObjCMTOpts = ObjCMTAction;
2019 std::vector<std::string> AllowList =
2021 return std::make_unique<ObjCMigrateASTConsumer>(
2030 unsigned Offset = 0;
2031 unsigned RemoveLen = 0;
2037template<>
struct DenseMapInfo<EditEntry> {
2049 return (
unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
2052 static bool isEqual(
const EditEntry &LHS,
const EditEntry &RHS) {
2053 return LHS.File == RHS.File &&
2054 LHS.Offset == RHS.Offset &&
2055 LHS.RemoveLen == RHS.RemoveLen &&
2056 LHS.Text == RHS.Text;
2062class RemapFileParser {
2066 RemapFileParser(
FileManager &FileMgr) : FileMgr(FileMgr) { }
2071 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
2072 llvm::MemoryBuffer::getFile(
File);
2077 Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(),
SM);
2078 document_iterator I = YAMLStream.begin();
2079 if (I == YAMLStream.end())
2081 Node *Root = I->getRoot();
2085 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
2089 for (SequenceNode::iterator
2090 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
2091 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
2094 parseEdit(MapNode, Entries);
2101 void parseEdit(llvm::yaml::MappingNode *
Node,
2105 bool Ignore =
false;
2107 for (MappingNode::iterator
2108 KVI =
Node->begin(), KVE =
Node->end(); KVI != KVE; ++KVI) {
2109 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
2113 StringRef Key = KeyString->getValue(KeyStorage);
2115 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
2119 StringRef Val = ValueString->getValue(ValueStorage);
2121 if (Key ==
"file") {
2126 }
else if (Key ==
"offset") {
2127 if (Val.getAsInteger(10, Entry.Offset))
2129 }
else if (Key ==
"remove") {
2130 if (Val.getAsInteger(10, Entry.RemoveLen))
2132 }
else if (Key ==
"text") {
2133 Entry.Text = std::string(Val);
2138 Entries.push_back(Entry);
2153 using namespace llvm::sys;
2160 I = Edits.begin(), E = Edits.end(); I != E; ++I) {
2161 const EditEntry &Entry = *I;
2162 assert(Entry.File == FE);
2164 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
2166 if (Entry.RemoveLen != 0) {
2168 Loc.getLocWithOffset(Entry.RemoveLen));
2172 if (
Range.isInvalid()) {
2174 }
else if (Entry.Text.empty()) {
2183 RewritesReceiver Rec(rewriter);
2188 llvm::raw_svector_ostream OS(NewText);
2193 if (fs::createTemporaryFile(path::filename(FE.
getName()),
2194 path::extension(FE.
getName()).drop_front(), FD,
2197 return std::string();
2200 llvm::raw_fd_ostream TmpOut(FD,
true);
2201 TmpOut.write(NewText.data(), NewText.size());
2204 return std::string(TempPath);
2208 std::vector<std::pair<std::string,std::string> > &remap,
2211 bool hasErrorOccurred =
false;
2215 RemapFileParser
Parser(FileMgr);
2220 DiagClient,
false));
2222 typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
2224 FileEditEntriesTy FileEditEntries;
2229 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
2231 if (
Parser.parse(*I, Entries))
2235 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
2236 EditEntry &Entry = *EI;
2239 std::pair<llvm::DenseSet<EditEntry>::iterator,
bool>
2240 Insert = EntriesSet.insert(Entry);
2244 FileEditEntries[*Entry.File].push_back(Entry);
2248 for (FileEditEntriesTy::iterator
2249 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
2252 if (TempFile.empty()) {
2253 hasErrorOccurred =
true;
2257 remap.emplace_back(std::string(I->first.getName()), TempFile);
2260 return hasErrorOccurred;
Defines the clang::ASTContext interface.
static Decl::Kind getKind(const Decl *D)
Defines the clang::FileManager interface and associated types.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static bool IsVoidStarType(QualType Ty)
static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, llvm::SmallVectorImpl< ObjCProtocolDecl * > &ConformingProtocols, const NSAPI &NS, edit::Commit &commit)
static bool AuditedType(QualType AT)
AuditedType - This routine audits the type AT and returns false if it is one of known CF object types...
static bool IsValidIdentifier(ASTContext &Ctx, const char *Name)
static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag)
static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2)
AvailabilityAttrsMatch - This routine checks that if comparing two availability attributes,...
static const char * PropertyMemoryAttribute(ASTContext &Context, QualType ArgType)
static void ReplaceWithInstancetype(ASTContext &Ctx, const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, const NSAPI &NS, edit::Commit &commit, unsigned LengthOfPrefix, bool Atomic, bool UseNsIosOnlyMacro, bool AvailabilityArgsMatch)
static bool TypeIsInnerPointer(QualType T)
static StringRef GetUnsignedName(StringRef NSIntegerName)
static bool hasSuperInitCall(const ObjCMethodDecl *MD)
static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D)
static std::string applyEditsToTemp(FileEntryRef FE, ArrayRef< EditEntry > Edits, FileManager &FileMgr, DiagnosticsEngine &Diag)
static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y)
Check whether the two versions match.
static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, bool &AvailabilityArgsMatch)
AttributesMatch - This routine checks list of attributes for two decls.
static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, StringRef NSIntegerName, bool NSOptions)
static void rewriteToNSMacroDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType)
static bool ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl, const ObjCInterfaceDecl *IDecl, ObjCProtocolDecl *Protocol)
static void append_attr(std::string &PropertyString, const char *attr, bool &LParenAdded)
static void MigrateBlockOrFunctionPointerTypeVariable(std::string &PropertyString, const std::string &TypeString, const char *name)
static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
static std::vector< std::string > getAllowListFilenames(StringRef DirPath)
static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, const EnumDecl *EnumDcl)
static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2, bool &AvailabilityArgsMatch)
Defines the clang::Preprocessor interface.
static bool subscriptOperatorNeedsParens(const Expr *FullExpr)
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D)
Handle the specified top-level declaration that occurred inside and ObjC container.
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
virtual void Initialize(ASTContext &Context)
Initialize - This is called to initialize the consumer, providing the ASTContext.
virtual void HandleInterestingDecl(DeclGroupRef D)
HandleInterestingDecl - Handle the specified interesting declaration.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodImp)
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
const LangOptions & getLangOpts() const
QualType getObjCInstanceType()
Retrieve the Objective-C "instancetype" type, if already known; otherwise, returns a NULL type;.
QualType getQualifiedType(SplitQualType split) const
Un-split a SplitQualType.
const clang::PrintingPolicy & getPrintingPolicy() const
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
DiagnosticsEngine & getDiagnostics() const
void CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet< ObjCProtocolDecl *, 8 > &Protocols)
CollectInheritedProtocols - Collect all protocols in current class and those inherited by it.
An instance of this class corresponds to a call.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
FileManager & getFileManager() const
Return the current file manager to the caller.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
SourceManager & getSourceManager() const
Return the current source manager.
The results of name lookup within a DeclContext.
decl_iterator - Iterates through the declarations stored within this context.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
decl_iterator decls_end() const
decl_iterator decls_begin() const
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
bool isDeprecated(std::string *Message=nullptr) const
Determine whether this declaration is marked 'deprecated'.
SourceLocation getBeginLoc() const LLVM_READONLY
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
enumerator_range enumerators() const
QualType getIntegerType() const
Return the integer type this enum decl corresponds to.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getName() const
The name of this FileEntry.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
bool FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
Keeps track of options that affect how file operations are performed.
std::string ObjCMTAllowListPath
std::string OutputFile
The output file, if any.
@ ObjCMT_Instancetype
Enable migration of ObjC methods to 'instancetype'.
@ ObjCMT_DesignatedInitializer
Enable inferring NS_DESIGNATED_INITIALIZER for ObjC methods.
@ ObjCMT_Annotation
Enable annotation of ObjCMethods of all kinds.
@ ObjCMT_PropertyDotSyntax
Enable converting setter/getter expressions to property-dot syntx.
@ ObjCMT_ProtocolConformance
Enable migration to add conforming protocols.
@ ObjCMT_NsMacros
Enable migration to NS_ENUM/NS_OPTIONS macros.
@ ObjCMT_AtomicProperty
prefer 'atomic' property over 'nonatomic'.
@ ObjCMT_Literals
Enable migration to modern ObjC literals.
@ ObjCMT_ReadonlyProperty
Enable migration to modern ObjC readonly property.
@ ObjCMT_Subscripting
Enable migration to modern ObjC subscripting.
@ ObjCMT_NsAtomicIOSOnlyProperty
use NS_NONATOMIC_IOSONLY for property 'atomic' attribute
@ ObjCMT_ReadwriteProperty
Enable migration to modern ObjC readwrite property.
@ ObjCMT_ReturnsInnerPointerProperty
annotate property with NS_RETURNS_INNER_POINTER
FullExpr - Represents a "full-expression" node.
Represents a function declaration or definition.
param_iterator param_end()
QualType getReturnType() const
param_iterator param_begin()
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
tok::TokenKind getTokenID() const
If this is a source-language token (e.g.
StringRef getName() const
Return the actual identifier string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isMacroDefined(StringRef Id) const
Returns true if Id is currently defined as a macro.
ASTContext & getASTContext() const
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
ObjCCategoryDecl - Represents a category declaration.
ObjCCategoryImplDecl - An object of this class encapsulates a category @implementation declaration.
ObjCContainerDecl - Represents a container for method declarations.
ObjCMethodDecl * getMethod(Selector Sel, bool isInstance, bool AllowHidden=false) const
method_range methods() const
instmeth_range instance_methods() const
instprop_range instance_properties() const
ObjCMethodDecl * getInstanceMethod(Selector Sel, bool AllowHidden=false) const
ObjCPropertyImplDecl * FindPropertyImplDecl(IdentifierInfo *propertyId, ObjCPropertyQueryKind queryKind) const
FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl added to the list of thos...
const ObjCInterfaceDecl * getClassInterface() const
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Represents an ObjC class declaration.
ObjCInterfaceDecl * lookupInheritedClass(const IdentifierInfo *ICName)
lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super class whose name is passe...
protocol_loc_iterator protocol_loc_end() const
SourceLocation getSuperClassLoc() const
Retrieve the starting location of the superclass.
const ObjCProtocolList & getReferencedProtocols() const
ObjCProtocolDecl * lookupNestedProtocol(IdentifierInfo *Name)
bool hasDesignatedInitializers() const
Returns true if this interface decl contains at least one initializer marked with the 'objc_designate...
ObjCInterfaceDecl * getSuperClass() const
ObjCList - This is a simple template class used to hold various lists of decls etc,...
An expression that sends a message to the given Objective-C object or class.
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Expr ** getArgs()
Retrieve the arguments to this message, not including the receiver.
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
SourceLocation getSuperLoc() const
Retrieve the location of the 'super' keyword for a class or instance message to 'super',...
ObjCMethodFamily getMethodFamily() const
@ SuperInstance
The receiver is the instance of the superclass object.
@ Instance
The receiver is an object instance.
const ObjCMethodDecl * getMethodDecl() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
SourceLocation getSelectorLoc(unsigned Index) const
unsigned getNumArgs() const
Return the number of actual arguments in this message, not counting the receiver.
ObjCMethodDecl - Represents an instance or class method declaration.
bool hasBody() const override
Determine whether this method has a body.
unsigned param_size() const
bool isPropertyAccessor() const
const ObjCPropertyDecl * findPropertyDecl(bool CheckOverrides=true) const
Returns the property associated with this method's selector.
param_const_iterator param_end() const
SourceLocation getSelectorStartLoc() const
param_const_iterator param_begin() const
Stmt * getBody() const override
Retrieve the body of this method, if it has one.
SourceLocation getEndLoc() const LLVM_READONLY
TypeSourceInfo * getReturnTypeSourceInfo() const
const ParmVarDecl *const * param_const_iterator
SourceLocation getBeginLoc() const LLVM_READONLY
Selector getSelector() const
bool isInstanceMethod() const
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
QualType getReturnType() const
ObjCInterfaceDecl * getClassInterface()
SourceLocation getDeclaratorEndLoc() const
Returns the location where the declarator ends.
Represents a pointer to an Objective C object.
Represents one property declaration in an Objective-C interface.
Represents an Objective-C protocol declaration.
ObjCProtocolDecl * lookupProtocolNamed(IdentifierInfo *PName)
ObjCProtocolDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C protocol.
Records preprocessor conditional directive regions and allows querying in which region source locatio...
Represents a parameter to a function.
Parser - This implements a parser for the C family of languages.
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, SourceLocation Loc)
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
IdentifierTable & getIdentifierTable()
bool getRawToken(SourceLocation Loc, Token &Result, bool IgnoreWhiteSpace=false)
Relex the token at the specified location.
SelectorTable & getSelectorTable()
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Computes the source location just past the end of the token at this source location.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
The collection of all-type qualifiers we support.
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
@ OCL_None
There is no lifetime qualification on this type.
@ OCL_Weak
Reading or writing from this object requires a barrier call.
void removeObjCLifetime()
bool hasObjCLifetime() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getDecl() const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
RewriteBuffer - As code is rewritten, SourceBuffer's from the original input with modifications get a...
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer.
Rewriter - This is the main interface to the rewrite buffers.
const RewriteBuffer * getRewriteBufferFor(FileID FID) const
getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
std::map< FileID, RewriteBuffer >::iterator buffer_iterator
static Selector constructSetterSelector(IdentifierTable &Idents, SelectorTable &SelTable, const IdentifierInfo *Name)
Return the default setter selector for the given identifier.
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
static ObjCInstanceTypeFamily getInstTypeMethodFamily(Selector sel)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
SourceRange getBraceRange() const
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Token - This structure provides full information about a lexed token.
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
unsigned getLength() const
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
The top declaration context.
SourceLocation getBeginLoc() const LLVM_READONLY
Base wrapper for a particular "section" of type source info.
SourceLocation getEndLoc() const
Get the end source location.
SourceLocation getBeginLoc() const
Get the begin source location.
A container of type source information.
QualType getType() const
Return the type wrapped by this type source info.
bool isBlockPointerType() const
bool isObjCBuiltinType() const
bool isFunctionPointerType() const
bool isPointerType() const
const T * castAs() const
Member-template castAs<specific type>.
bool isObjCIdType() const
bool isObjCObjectPointerType() const
bool isAnyPointerType() const
const T * getAs() const
Member-template getAs<specific type>'.
bool isObjCRetainableType() const
Represents the declaration of a typedef-name via the 'typedef' type specifier.
TypeSourceInfo * getTypeSourceInfo() const
A frontend action which simply wraps some other runtime-specified frontend action.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag)
bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag)
void remap(StringRef filePath, std::unique_ptr< llvm::MemoryBuffer > memBuf)
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged)
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
ObjCMigrateAction(std::unique_ptr< FrontendAction > WrappedAction, StringRef migrateDir, unsigned migrateAction)
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool insertWrap(StringRef before, CharSourceRange range, StringRef after)
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
bool insertAfterToken(SourceLocation loc, StringRef text, bool beforePreviousInsertions=false)
bool remove(CharSourceRange range)
bool insertBefore(SourceLocation loc, StringRef text)
bool replace(CharSourceRange range, StringRef text)
void applyRewrites(EditsReceiver &receiver, bool adjustRemovals=true)
bool commit(const Commit &commit)
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
ObjKind getObjKind() const
ArgEffectKind getKind() const
A Range represents the closed range [from, to].
RetEffect summarizes a call's retain/release behavior with respect to its return value.
Summary for a function with respect to ownership changes.
ArgEffect getReceiverEffect() const
getReceiverEffect - Returns the effect on the receiver of the call.
RetEffect getRetEffect() const
getRetEffect - Returns the effect on the return value of the call.
ArgEffect getArg(unsigned idx) const
getArg - Return the argument effect on the argument specified by idx (starting from 0).
SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
bool getFileRemappingsFromFileList(std::vector< std::pair< std::string, std::string > > &remap, ArrayRef< StringRef > remapFiles, DiagnosticConsumer *DiagClient)
Get the set of file remappings from a list of files with remapping info.
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit, const ParentMap *PMap)
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
bool isCFObjectRef(QualType T)
@ IncRef
The argument has its reference count increased by 1.
@ DecRef
The argument has its reference count decreased by 1.
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
The JSON file list parser is used to communicate input to InstallAPI.
@ Rewrite
We are substituting template parameters for (typically) other template parameters in order to rewrite...
LLVM_READONLY char toLowercase(char c)
Converts the given ASCII character to its lowercase equivalent.
LLVM_READONLY bool isUppercase(unsigned char c)
Return true if this character is an uppercase ASCII letter: [A-Z].
ObjCMethodFamily
A family of Objective-C methods.
@ Property
The type of a property.
ObjCInstanceTypeFamily
A family of Objective-C methods.
LLVM_READONLY bool isAsciiIdentifierStart(unsigned char c, bool AllowDollar=false)
Returns true if this is a valid first character of a C identifier, which is [a-zA-Z_].
YAML serialization mapping.
Describes how types, statements, expressions, and declarations should be printed.
unsigned SuppressStrongLifetime
When true, suppress printing of the __strong lifetime qualifier in ARC.
unsigned SuppressLifetimeQualifiers
When true, suppress printing of lifetime qualifier in ARC.
static bool isEqual(const EditEntry &LHS, const EditEntry &RHS)
static EditEntry getTombstoneKey()
static unsigned getHashValue(const EditEntry &Val)
static EditEntry getEmptyKey()