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) {
127 for (
const std::string &Val : AllowList)
128 AllowListFilenames.insert(Val);
133 NSAPIObj.reset(
new NSAPI(Context));
148 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
153 bool canModifyFile(StringRef Path) {
154 if (AllowListFilenames.empty())
156 return AllowListFilenames.contains(llvm::sys::path::filename(Path));
161 return canModifyFile(FE->
getName());
163 bool canModifyFile(
FileID FID) {
169 bool canModify(
const Decl *D) {
173 return canModify(CatImpl->getCategoryDecl());
175 return canModify(Impl->getClassInterface());
177 return canModify(cast<Decl>(MD->getDeclContext()));
180 return canModifyFile(FID);
187 std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
188 unsigned migrateAction)
190 ObjCMigAction(migrateAction), CompInst(nullptr) {
191 if (MigrateDir.empty())
195std::unique_ptr<ASTConsumer>
200 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
202 Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
203 MigrateDir, ObjCMigAction, Remapper, CompInst->
getFileManager(), PPRec,
205 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
220 return !(isa<ArraySubscriptExpr>(
Expr) || isa<CallExpr>(
Expr) ||
221 isa<DeclRefExpr>(
Expr) || isa<CXXNamedCastExpr>(
Expr) ||
222 isa<CXXConstructExpr>(
Expr) || isa<CXXThisExpr>(
Expr) ||
223 isa<CXXTypeidExpr>(
Expr) ||
224 isa<CXXUnresolvedConstructExpr>(
Expr) ||
225 isa<ObjCMessageExpr>(
Expr) || isa<ObjCPropertyRefExpr>(
Expr) ||
226 isa<ObjCProtocolExpr>(
Expr) || isa<MemberExpr>(
Expr) ||
227 isa<ObjCIvarRefExpr>(
Expr) || isa<ParenExpr>(
FullExpr) ||
228 isa<ParenListExpr>(
Expr) || isa<SizeOfPackExpr>(
Expr));
242 if (Receiver->getType()->isObjCBuiltinType())
256 bool ReceiverIsSuper =
270 std::string PropertyDotString;
275 PropertyDotString =
").";
278 PropertyDotString =
".";
279 PropertyDotString += Prop->
getName();
280 commit.
replace(SpaceRange, PropertyDotString);
288 std::string PropertyDotString =
".";
289 PropertyDotString += Prop->
getName();
290 PropertyDotString +=
" =";
292 const Expr *RHS = Args[0];
302 if (colon && colon[0] ==
':')
303 PropertyDotString +=
" ";
314 ObjCMigrateASTConsumer &Consumer;
318 ObjCMigrator(ObjCMigrateASTConsumer &consumer,
ParentMap &PMap)
319 : Consumer(consumer), PMap(PMap) { }
321 bool shouldVisitTemplateInstantiations()
const {
return false; }
322 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
328 Consumer.Editor->commit(commit);
334 Consumer.Editor->commit(commit);
339 rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
341 Consumer.Editor->commit(commit);
351 if (!TraverseStmt(SubStmt))
354 return WalkUpFromObjCMessageExpr(E);
359 ObjCMigrateASTConsumer &Consumer;
360 std::unique_ptr<ParentMap> PMap;
363 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
365 bool shouldVisitTemplateInstantiations()
const {
return false; }
366 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
368 bool TraverseStmt(
Stmt *S) {
370 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
376void ObjCMigrateASTConsumer::migrateDecl(
Decl *D) {
379 if (isa<ObjCMethodDecl>(D))
382 BodyMigrator(*this).TraverseDecl(D);
385static void append_attr(std::string &PropertyString,
const char *attr,
388 PropertyString +=
"(";
392 PropertyString +=
", ";
393 PropertyString +=
attr;
398 const std::string& TypeString,
400 const char *argPtr = TypeString.c_str();
405 PropertyString += *argPtr;
409 PropertyString += *argPtr;
414 PropertyString += (*argPtr);
416 PropertyString += name;
421 PropertyString += *argPtr;
431 if (RetainableObject &&
449 else if (RetainableObject)
457 unsigned LengthOfPrefix,
458 bool Atomic,
bool UseNsIosOnlyMacro,
459 bool AvailabilityArgsMatch) {
461 bool LParenAdded =
false;
462 std::string PropertyString =
"@property ";
463 if (UseNsIosOnlyMacro && NS.
isMacroDefined(
"NS_NONATOMIC_IOSONLY")) {
464 PropertyString +=
"(NS_NONATOMIC_IOSONLY";
466 }
else if (!Atomic) {
467 PropertyString +=
"(nonatomic";
472 StringRef PropertyName(PropertyNameString);
473 if (LengthOfPrefix > 0) {
475 PropertyString +=
"(getter=";
479 PropertyString +=
", getter=";
480 PropertyString += PropertyNameString;
484 append_attr(PropertyString,
"readonly", LParenAdded);
489 if (PropertyName.equals(
"target") || PropertyName.contains(
"delegate") ||
490 PropertyName.contains(
"dataSource")) {
493 append_attr(PropertyString,
"assign", LParenAdded);
494 }
else if (!Setter) {
497 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
502 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
505 PropertyString +=
')';
516 PropertyString +=
" ";
520 std::string TypeString = RT.
getAsString(SubPolicy);
521 if (LengthOfPrefix > 0) {
524 StringRef PropertyNameStringRef(PropertyNameString);
525 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
526 PropertyNameString = std::string(PropertyNameStringRef);
527 bool NoLowering = (
isUppercase(PropertyNameString[0]) &&
528 PropertyNameString.size() > 1 &&
531 PropertyNameString[0] =
toLowercase(PropertyNameString[0]);
536 PropertyNameString.c_str());
538 char LastChar = TypeString[TypeString.size()-1];
539 PropertyString += TypeString;
541 PropertyString +=
' ';
542 PropertyString += PropertyNameString;
550 EndGetterSelectorLoc),
552 if (Setter && AvailabilityArgsMatch) {
566 StringRef Name = CatDecl->getName();
567 return Name.endswith(
"Deprecated");
572void ObjCMigrateASTConsumer::migrateObjCContainerDecl(
ASTContext &Ctx,
577 for (
auto *Method : D->
methods()) {
580 bool PropertyInferred = migrateProperty(Ctx, D, Method);
584 if (!PropertyInferred ||
587 migrateNsReturnsInnerPointer(Ctx, Method);
595 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
607 bool HasAtleastOneRequiredProperty =
false;
609 for (
const auto *
Property : PDecl->instance_properties()) {
612 HasAtleastOneRequiredProperty =
true;
619 Property->getDeclName().getAsIdentifierInfo(),
623 if ((ClassProperty->getPropertyAttributes() !=
624 Property->getPropertyAttributes()) ||
634 bool HasAtleastOneRequiredMethod =
false;
636 if (PDecl->meth_begin() == PDecl->meth_end())
637 return HasAtleastOneRequiredProperty;
638 for (
const auto *MD : PDecl->methods()) {
639 if (MD->isImplicit())
647 HasAtleastOneRequiredMethod =
true;
658 return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
665 std::string ClassString;
669 if (Protocols.
empty()) {
671 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
672 ClassString += ConformingProtocols[i]->getNameAsString();
680 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
681 ClassString += ConformingProtocols[i]->getNameAsString();
694 StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
695 .Case(
"int8_t",
"uint8_t")
696 .Case(
"int16_t",
"uint16_t")
697 .Case(
"int32_t",
"uint32_t")
698 .Case(
"NSInteger",
"NSUInteger")
699 .Case(
"int64_t",
"uint64_t")
700 .Default(NSIntegerName);
707 StringRef NSIntegerName,
709 std::string ClassString;
711 ClassString =
"typedef NS_OPTIONS(";
715 ClassString =
"typedef NS_ENUM(";
716 ClassString += NSIntegerName;
723 commit.
replace(R, ClassString);
727 if (EndOfEnumDclLoc.
isValid()) {
737 if (EndTypedefDclLoc.
isValid()) {
747 if (EndOfEnumDclLoc.
isValid()) {
762 bool IsNSIntegerType) {
764 assert(!DesignatedEnumType.
isNull()
765 &&
"rewriteToNSMacroDecl - underlying enum type is null");
768 std::string TypeString = DesignatedEnumType.
getAsString(Policy);
769 std::string ClassString = IsNSIntegerType ?
"NS_ENUM(" :
"NS_OPTIONS(";
770 ClassString += TypeString;
780 commit.
replace(R, ClassString);
791 bool PowerOfTwo =
true;
792 bool AllHexdecimalEnumerator =
true;
793 uint64_t MaxPowerOfTwoVal = 0;
795 const Expr *InitExpr = Enumerator->getInitExpr();
798 AllHexdecimalEnumerator =
false;
802 if (
const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
803 if (BO->isShiftOp() || BO->isBitwiseOp())
806 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
807 if (PowerOfTwo && EnumVal) {
808 if (!llvm::isPowerOf2_64(EnumVal))
810 else if (EnumVal > MaxPowerOfTwoVal)
811 MaxPowerOfTwoVal = EnumVal;
813 if (AllHexdecimalEnumerator && EnumVal) {
814 bool FoundHexdecimalEnumerator =
false;
820 FoundHexdecimalEnumerator =
821 (StringLit[0] ==
'0' && (
toLowercase(StringLit[1]) ==
'x'));
823 if (!FoundHexdecimalEnumerator)
824 AllHexdecimalEnumerator =
false;
827 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
830void ObjCMigrateASTConsumer::migrateProtocolConformance(
ASTContext &Ctx,
833 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->
isDeprecated())
842 if (!ExplicitProtocols.count(ProtDecl))
843 PotentialImplicitProtocols.push_back(ProtDecl);
845 if (PotentialImplicitProtocols.empty())
852 for (
unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
854 PotentialImplicitProtocols[i]))
855 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
857 if (ConformingProtocols.empty())
863 for (
unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
866 for (
unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
868 if (PDecl == TargetPDecl)
877 MinimalConformingProtocols.push_back(TargetPDecl);
879 if (MinimalConformingProtocols.empty())
884 Editor->commit(commit);
887void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
891 if (NSAPIObj->isObjCNSIntegerType(qt))
892 NSIntegerTypedefed = TypedefDcl;
893 else if (NSAPIObj->isObjCNSUIntegerType(qt))
894 NSUIntegerTypedefed = TypedefDcl;
897bool ObjCMigrateASTConsumer::migrateNSEnumDecl(
ASTContext &Ctx,
904 if (NSIntegerTypedefed) {
905 TypedefDcl = NSIntegerTypedefed;
906 NSIntegerTypedefed =
nullptr;
908 else if (NSUIntegerTypedefed) {
909 TypedefDcl = NSUIntegerTypedefed;
910 NSUIntegerTypedefed =
nullptr;
914 FileID FileIdOfTypedefDcl =
918 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
925 StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
927 if (NSIntegerName.empty()) {
930 if (EnumTy->getDecl() == EnumDcl) {
932 if (!InsertFoundation(Ctx, TypedefDcl->
getBeginLoc()))
936 Editor->commit(commit);
945 if (!InsertFoundation(Ctx, TypedefDcl->
getBeginLoc()))
949 commit, NSIntegerName, NSOptions);
950 Editor->commit(commit);
955 const ObjCMigrateASTConsumer &ASTC,
961 std::string ClassString;
963 TypeLoc TL = TSInfo->getTypeLoc();
965 ClassString =
"instancetype";
970 ClassString +=
" (instancetype)";
973 commit.
replace(R, ClassString);
974 ASTC.Editor->commit(commit);
981 std::string ClassString;
983 TypeLoc TL = TSInfo->getTypeLoc();
985 ClassString = std::string(IDecl->
getName());
992 ClassString += IDecl->
getName(); ClassString +=
"*)";
995 commit.
replace(R, ClassString);
996 ASTC.Editor->commit(commit);
999void ObjCMigrateASTConsumer::migrateMethodInstanceType(
ASTContext &Ctx,
1005 std::string ClassName;
1006 switch (OIT_Family) {
1008 migrateFactoryMethod(Ctx, CDecl, OM);
1011 ClassName =
"NSArray";
1014 ClassName =
"NSDictionary";
1033 IDecl = CatDecl->getClassInterface();
1034 else if (
ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1039 migrateFactoryMethod(Ctx, CDecl, OM);
1056 T = TD->getDecl()->getUnderlyingType();
1061 if (UPointeeT->isRecordType()) {
1080 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
1083 const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
1085 VersionTuple Introduced1 = AA1->getIntroduced();
1086 VersionTuple Deprecated1 = AA1->getDeprecated();
1087 VersionTuple Obsoleted1 = AA1->getObsoleted();
1088 bool IsUnavailable1 = AA1->getUnavailable();
1089 VersionTuple Introduced2 = AA2->getIntroduced();
1090 VersionTuple Deprecated2 = AA2->getDeprecated();
1091 VersionTuple Obsoleted2 = AA2->getObsoleted();
1092 bool IsUnavailable2 = AA2->getUnavailable();
1096 IsUnavailable1 == IsUnavailable2);
1100 bool &AvailabilityArgsMatch) {
1102 for (
unsigned i = 0, e = Attrs1.size(); i != e; i++) {
1104 for (
unsigned j = 0, f = Attrs2.size(); j != f; j++) {
1109 if (AvailabilityArgsMatch)
1129 bool &AvailabilityArgsMatch) {
1134 AvailabilityArgsMatch =
true;
1138 if (
match && (Attrs2.size() > Attrs1.size()))
1147 std::string NameString = Name;
1153bool ObjCMigrateASTConsumer::migrateProperty(
ASTContext &Ctx,
1177 unsigned LengthOfPrefix = 0;
1178 if (!SetterMethod) {
1180 StringRef getterNameString = getterName->
getName();
1181 bool IsPrefix = getterNameString.startswith(
"is");
1186 if (IsPrefix || getterNameString.startswith(
"get")) {
1187 LengthOfPrefix = (IsPrefix ? 2 : 3);
1188 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1193 if (CGetterName[0] &&
isUppercase(CGetterName[0])) {
1194 getterName = &Ctx.
Idents.
get(CGetterName);
1207 bool AvailabilityArgsMatch;
1223 (ASTMigrateActions &
1225 (ASTMigrateActions &
1227 AvailabilityArgsMatch);
1228 Editor->commit(commit);
1237 (ASTMigrateActions &
1239 (ASTMigrateActions &
1242 Editor->commit(commit);
1248void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(
ASTContext &Ctx,
1252 OM->
hasAttr<ObjCReturnsInnerPointerAttr>())
1257 !NSAPIObj->isMacroDefined(
"NS_RETURNS_INNER_POINTER"))
1262 Editor->commit(commit);
1265void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(
ASTContext &Ctx,
1270 !NSAPIObj->isMacroDefined(
"NS_RETURNS_INNER_POINTER"))
1273 commit.
insertBefore(
P->getEndLoc(),
" NS_RETURNS_INNER_POINTER ");
1274 Editor->commit(commit);
1277void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(
ASTContext &Ctx,
1283 for (
auto *Method : CDecl->
methods()) {
1286 migrateMethodInstanceType(Ctx, CDecl, Method);
1290void ObjCMigrateASTConsumer::migrateFactoryMethod(
ASTContext &Ctx,
1304 IDecl = CatDecl->getClassInterface();
1305 else if (
ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1311 std::string StringClassName = std::string(IDecl->
getName());
1312 StringRef LoweredClassName(StringClassName);
1313 std::string StringLoweredClassName = LoweredClassName.lower();
1314 LoweredClassName = StringLoweredClassName;
1321 std::string MethodName = std::string(MethodIdName->
getName());
1323 StringRef STRefMethodName(MethodName);
1325 if (STRefMethodName.startswith(
"standard"))
1326 len = strlen(
"standard");
1327 else if (STRefMethodName.startswith(
"shared"))
1328 len = strlen(
"shared");
1329 else if (STRefMethodName.startswith(
"default"))
1330 len = strlen(
"default");
1333 MethodName = std::string(STRefMethodName.substr(len));
1335 std::string MethodNameSubStr = MethodName.substr(0, 3);
1336 StringRef MethodNamePrefix(MethodNameSubStr);
1337 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1338 MethodNamePrefix = StringLoweredMethodNamePrefix;
1339 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1340 if (Ix == StringRef::npos)
1342 std::string ClassNamePostfix = std::string(LoweredClassName.substr(Ix));
1343 StringRef LoweredMethodName(MethodName);
1344 std::string StringLoweredMethodName = LoweredMethodName.lower();
1345 LoweredMethodName = StringLoweredMethodName;
1346 if (!LoweredMethodName.startswith(ClassNamePostfix))
1382void ObjCMigrateASTConsumer::AnnotateImplicitBridging(
ASTContext &Ctx) {
1383 if (CFFunctionIBCandidates.empty())
1385 if (!NSAPIObj->isMacroDefined(
"CF_IMPLICIT_BRIDGING_ENABLED")) {
1386 CFFunctionIBCandidates.clear();
1391 const Decl *FirstFD = CFFunctionIBCandidates[0];
1392 const Decl *LastFD =
1393 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
1394 const char *PragmaString =
"\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1397 PragmaString =
"\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1401 if (isa<FunctionDecl>(LastFD)) {
1411 Editor->commit(commit);
1413 CFFunctionIBCandidates.clear();
1421 assert(CFFunctionIBCandidates.empty() &&
1422 "Cannot have audited functions/methods inside user "
1423 "provided CF_IMPLICIT_BRIDGING_ENABLE");
1429 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1430 if (AuditKind == CF_BRIDGING_ENABLE) {
1431 CFFunctionIBCandidates.push_back(
Decl);
1435 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1436 if (!CFFunctionIBCandidates.empty()) {
1437 CFFunctionIBCandidates.push_back(
Decl);
1443 AnnotateImplicitBridging(Ctx);
1446 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(
Decl));
1447 AnnotateImplicitBridging(Ctx);
1451void ObjCMigrateASTConsumer::AddCFAnnotations(
ASTContext &Ctx,
1454 bool ResultAnnotated) {
1456 if (!ResultAnnotated) {
1458 const char *AnnotationString =
nullptr;
1459 if (
Ret.getObjKind() == ObjKind::CF) {
1460 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"CF_RETURNS_RETAINED"))
1461 AnnotationString =
" CF_RETURNS_RETAINED";
1462 else if (
Ret.notOwned() &&
1463 NSAPIObj->isMacroDefined(
"CF_RETURNS_NOT_RETAINED"))
1464 AnnotationString =
" CF_RETURNS_NOT_RETAINED";
1466 else if (
Ret.getObjKind() == ObjKind::ObjC) {
1467 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"NS_RETURNS_RETAINED"))
1468 AnnotationString =
" NS_RETURNS_RETAINED";
1471 if (AnnotationString) {
1474 Editor->commit(commit);
1479 pe = FuncDecl->
param_end(); pi != pe; ++pi, ++i) {
1483 !pd->
hasAttr<CFConsumedAttr>() &&
1484 NSAPIObj->isMacroDefined(
"CF_CONSUMED")) {
1487 Editor->commit(commit);
1489 !pd->
hasAttr<NSConsumedAttr>() &&
1490 NSAPIObj->isMacroDefined(
"NS_CONSUMED")) {
1493 Editor->commit(commit);
1498ObjCMigrateASTConsumer::CF_BRIDGING_KIND
1499 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1503 return CF_BRIDGING_NONE;
1506 getSummaryManager(Ctx).getSummary(
AnyCall(FuncDecl));
1507 bool FuncIsReturnAnnotated = (FuncDecl->
hasAttr<CFReturnsRetainedAttr>() ||
1508 FuncDecl->
hasAttr<CFReturnsNotRetainedAttr>() ||
1509 FuncDecl->
hasAttr<NSReturnsRetainedAttr>() ||
1510 FuncDecl->
hasAttr<NSReturnsNotRetainedAttr>() ||
1511 FuncDecl->
hasAttr<NSReturnsAutoreleasedAttr>());
1514 if (FuncIsReturnAnnotated && FuncDecl->
getNumParams() == 0)
1515 return CF_BRIDGING_NONE;
1517 bool ReturnCFAudited =
false;
1518 if (!FuncIsReturnAnnotated) {
1520 if (
Ret.getObjKind() == ObjKind::CF &&
1521 (
Ret.isOwned() ||
Ret.notOwned()))
1522 ReturnCFAudited =
true;
1524 return CF_BRIDGING_NONE;
1529 bool ArgCFAudited =
false;
1531 pe = FuncDecl->
param_end(); pi != pe; ++pi, ++i) {
1537 ArgCFAudited =
true;
1539 ArgCFAudited =
true;
1543 AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
1544 return CF_BRIDGING_NONE;
1548 if (ReturnCFAudited || ArgCFAudited)
1549 return CF_BRIDGING_ENABLE;
1551 return CF_BRIDGING_MAY_INCLUDE;
1554void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(
ASTContext &Ctx,
1556 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->
isDeprecated())
1560 for (
const auto *Method : CDecl->
methods())
1561 migrateCFAnnotation(Ctx, Method);
1564void ObjCMigrateASTConsumer::AddCFAnnotations(
ASTContext &Ctx,
1567 bool ResultAnnotated) {
1569 if (!ResultAnnotated) {
1571 const char *AnnotationString =
nullptr;
1572 if (
Ret.getObjKind() == ObjKind::CF) {
1573 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"CF_RETURNS_RETAINED"))
1574 AnnotationString =
" CF_RETURNS_RETAINED";
1575 else if (
Ret.notOwned() &&
1576 NSAPIObj->isMacroDefined(
"CF_RETURNS_NOT_RETAINED"))
1577 AnnotationString =
" CF_RETURNS_NOT_RETAINED";
1579 else if (
Ret.getObjKind() == ObjKind::ObjC) {
1590 if (
Ret.isOwned() && NSAPIObj->isMacroDefined(
"NS_RETURNS_RETAINED"))
1591 AnnotationString =
" NS_RETURNS_RETAINED";
1596 if (AnnotationString) {
1599 Editor->commit(commit);
1604 pe = MethodDecl->
param_end(); pi != pe; ++pi, ++i) {
1609 && !pd->
hasAttr<CFConsumedAttr>() &&
1610 NSAPIObj->isMacroDefined(
"CF_CONSUMED")) {
1613 Editor->commit(commit);
1618void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
1625 getSummaryManager(Ctx).getSummary(
AnyCall(MethodDecl));
1627 bool MethodIsReturnAnnotated =
1628 (MethodDecl->
hasAttr<CFReturnsRetainedAttr>() ||
1629 MethodDecl->
hasAttr<CFReturnsNotRetainedAttr>() ||
1630 MethodDecl->
hasAttr<NSReturnsRetainedAttr>() ||
1631 MethodDecl->
hasAttr<NSReturnsNotRetainedAttr>() ||
1632 MethodDecl->
hasAttr<NSReturnsAutoreleasedAttr>());
1635 !MethodDecl->
hasAttr<NSConsumesSelfAttr>() &&
1638 NSAPIObj->isMacroDefined(
"NS_CONSUMES_SELF")) {
1641 Editor->commit(commit);
1645 if (MethodIsReturnAnnotated &&
1649 if (!MethodIsReturnAnnotated) {
1651 if ((
Ret.getObjKind() == ObjKind::CF ||
1652 Ret.getObjKind() == ObjKind::ObjC) &&
1653 (
Ret.isOwned() ||
Ret.notOwned())) {
1654 AddCFAnnotations(Ctx, RS, MethodDecl,
false);
1663 pe = MethodDecl->
param_end(); pi != pe; ++pi, ++i) {
1668 AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
1677 bool shouldVisitTemplateInstantiations()
const {
return false; }
1678 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
1691 return !SuperInitChecker().TraverseStmt(MD->
getBody());
1694void ObjCMigrateASTConsumer::inferDesignatedInitializers(
1701 if (!NSAPIObj->isMacroDefined(
"NS_DESIGNATED_INITIALIZER"))
1705 if (MD->isDeprecated() ||
1706 MD->getMethodFamily() !=
OMF_init ||
1707 MD->isDesignatedInitializerForTheInterface())
1716 Editor->commit(commit);
1721bool ObjCMigrateASTConsumer::InsertFoundation(
ASTContext &Ctx,
1723 if (FoundationIncluded)
1725 if (
Loc.isInvalid())
1727 auto *nsEnumId = &Ctx.
Idents.
get(
"NS_ENUM");
1729 FoundationIncluded =
true;
1734 commit.
insert(
Loc,
"#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
1736 commit.
insert(
Loc,
"#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
1737 Editor->commit(commit);
1738 FoundationIncluded =
true;
1751 Rewrite.InsertText(loc, text);
1760 llvm::raw_ostream &OS;
1764 : SourceMgr(
SM), OS(OS) {
1767 ~JSONEditWriter()
override { OS <<
"]\n"; }
1770 struct EntryWriter {
1772 llvm::raw_ostream &OS;
1775 : SourceMgr(
SM), OS(OS) {
1789 llvm::sys::fs::make_absolute(Path);
1790 OS <<
" \"file\": \"";
1791 OS.write_escaped(Path.str()) <<
"\",\n";
1792 OS <<
" \"offset\": " << Offset <<
",\n";
1796 assert(
Range.isCharRange());
1797 std::pair<FileID, unsigned>
Begin =
1799 std::pair<FileID, unsigned> End =
1801 assert(
Begin.first == End.first);
1802 assert(
Begin.second <= End.second);
1803 unsigned Length = End.second -
Begin.second;
1805 OS <<
" \"remove\": " << Length <<
",\n";
1808 void writeText(StringRef
Text) {
1809 OS <<
" \"text\": \"";
1810 OS.write_escaped(
Text) <<
"\",\n";
1815 EntryWriter Writer(SourceMgr, OS);
1816 Writer.writeLoc(
Loc);
1817 Writer.writeText(
Text);
1821 EntryWriter Writer(SourceMgr, OS);
1822 Writer.writeLoc(
Range.getBegin());
1823 Writer.writeRemove(
Range);
1824 Writer.writeText(
Text);
1828 EntryWriter Writer(SourceMgr, OS);
1829 Writer.writeLoc(
Range.getBegin());
1830 Writer.writeRemove(
Range);
1836void ObjCMigrateASTConsumer::HandleTranslationUnit(
ASTContext &Ctx) {
1844 if (FileId.
isValid() && FileId != FID) {
1846 AnnotateImplicitBridging(Ctx);
1850 if (canModify(CDecl))
1851 migrateObjCContainerDecl(Ctx, CDecl);
1853 if (canModify(CatDecl))
1854 migrateObjCContainerDecl(Ctx, CatDecl);
1858 if (canModify(PDecl))
1859 migrateObjCContainerDecl(Ctx, PDecl);
1862 dyn_cast<ObjCImplementationDecl>(*D)) {
1865 migrateProtocolConformance(Ctx, ImpDecl);
1867 else if (
const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1874 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1875 if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1879 migrateNSEnumDecl(Ctx, ED,
nullptr);
1881 else if (
const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
1889 if (
const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1890 if (canModify(ED)) {
1892 if (
const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
1894 if (migrateNSEnumDecl(Ctx, ED, TDF)) {
1896 CacheObjCNSIntegerTypedefed(TD);
1900 if (migrateNSEnumDecl(Ctx, ED, TD)) {
1906 CacheObjCNSIntegerTypedefed(TD);
1908 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1911 migrateCFAnnotation(Ctx, FD);
1915 bool CanModify = canModify(CDecl);
1919 migrateAllMethodInstaceType(Ctx, CDecl);
1923 migrateARCSafeAnnotation(Ctx, CDecl);
1927 ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
1930 inferDesignatedInitializers(Ctx, ImplD);
1934 AnnotateImplicitBridging(Ctx);
1939 llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
1948 Editor->applyRewrites(Writer);
1953 RewritesReceiver Rec(rewriter);
1954 Editor->applyRewrites(Rec);
1957 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1964 llvm::raw_svector_ostream vecOS(newText);
1966 std::unique_ptr<llvm::MemoryBuffer> memBuf(
1967 llvm::MemoryBuffer::getMemBufferCopy(
1968 StringRef(newText.data(), newText.size()), file->
getName()));
1971 Remapper.
remap(filePath.str(), std::move(memBuf));
1987 using namespace llvm::sys::fs;
1988 using namespace llvm::sys::path;
1990 std::vector<std::string> Filenames;
1991 if (DirPath.empty() || !is_directory(DirPath))
1995 directory_iterator DI = directory_iterator(DirPath, EC);
1996 directory_iterator DE;
1997 for (; !EC && DI != DE; DI = DI.increment(EC)) {
1998 if (is_regular_file(DI->path()))
1999 Filenames.push_back(std::string(filename(DI->path())));
2005std::unique_ptr<ASTConsumer>
2010 unsigned ObjCMTOpts = ObjCMTAction;
2021 std::vector<std::string> AllowList =
2023 return std::make_unique<ObjCMigrateASTConsumer>(
2032 unsigned Offset = 0;
2033 unsigned RemoveLen = 0;
2039template<>
struct DenseMapInfo<EditEntry> {
2051 return (
unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
2054 static bool isEqual(
const EditEntry &LHS,
const EditEntry &RHS) {
2055 return LHS.File == RHS.File &&
2056 LHS.Offset == RHS.Offset &&
2057 LHS.RemoveLen == RHS.RemoveLen &&
2058 LHS.Text == RHS.Text;
2064class RemapFileParser {
2068 RemapFileParser(
FileManager &FileMgr) : FileMgr(FileMgr) { }
2073 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
2074 llvm::MemoryBuffer::getFile(
File);
2079 Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(),
SM);
2080 document_iterator I = YAMLStream.begin();
2081 if (I == YAMLStream.end())
2083 Node *Root = I->getRoot();
2087 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
2091 for (SequenceNode::iterator
2092 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
2093 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
2096 parseEdit(MapNode, Entries);
2103 void parseEdit(llvm::yaml::MappingNode *
Node,
2107 bool Ignore =
false;
2109 for (MappingNode::iterator
2110 KVI =
Node->begin(), KVE =
Node->end(); KVI != KVE; ++KVI) {
2111 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
2115 StringRef Key = KeyString->getValue(KeyStorage);
2117 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
2121 StringRef Val = ValueString->getValue(ValueStorage);
2123 if (Key ==
"file") {
2128 }
else if (Key ==
"offset") {
2129 if (Val.getAsInteger(10, Entry.Offset))
2131 }
else if (Key ==
"remove") {
2132 if (Val.getAsInteger(10, Entry.RemoveLen))
2134 }
else if (Key ==
"text") {
2135 Entry.Text = std::string(Val);
2140 Entries.push_back(Entry);
2155 using namespace llvm::sys;
2162 I = Edits.begin(), E = Edits.end(); I != E; ++I) {
2163 const EditEntry &Entry = *I;
2164 assert(Entry.File == FE);
2166 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
2168 if (Entry.RemoveLen != 0) {
2170 Loc.getLocWithOffset(Entry.RemoveLen));
2174 if (
Range.isInvalid()) {
2176 }
else if (Entry.Text.empty()) {
2185 RewritesReceiver Rec(rewriter);
2190 llvm::raw_svector_ostream OS(NewText);
2195 if (fs::createTemporaryFile(path::filename(FE.
getName()),
2196 path::extension(FE.
getName()).drop_front(), FD,
2199 return std::string();
2202 llvm::raw_fd_ostream TmpOut(FD,
true);
2203 TmpOut.write(NewText.data(), NewText.size());
2206 return std::string(TempPath.str());
2210 std::vector<std::pair<std::string,std::string> > &remap,
2213 bool hasErrorOccurred =
false;
2217 RemapFileParser
Parser(FileMgr);
2222 DiagClient,
false));
2224 typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
2226 FileEditEntriesTy FileEditEntries;
2231 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
2233 if (
Parser.parse(*I, Entries))
2237 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
2238 EditEntry &Entry = *EI;
2241 std::pair<llvm::DenseSet<EditEntry>::iterator,
bool>
2242 Insert = EntriesSet.insert(Entry);
2246 FileEditEntries[*Entry.File].push_back(Entry);
2250 for (FileEditEntriesTy::iterator
2251 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
2254 if (TempFile.empty()) {
2255 hasErrorOccurred =
true;
2259 remap.emplace_back(std::string(I->first.getName()), TempFile);
2262 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)
@ 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()