Skip to content

Commit 319e8cd

Browse files
[Clang][Sema] clang generates incorrect fix-its for API_AVAILABLE (#105855)
Apple's API_AVAILABLE macro has its own notion of platform names which are supported by \_\_API_AVAILABLE_PLATFORM_<name> macros. They don't follow a consistent naming convention, but there's at least one that matches a valid availability attribute platform name. Instead of lowercasing the source spelling name, search for a defined macro and use that in the fix-it.
1 parent ec8e1c6 commit 319e8cd

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,36 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
10731073
.Case("ShaderModel", "shadermodel")
10741074
.Default(Platform);
10751075
}
1076+
static std::vector<llvm::StringRef> equivalentPlatformNames(llvm::StringRef Platform) {
1077+
return llvm::StringSwitch<std::vector<llvm::StringRef>>(Platform)
1078+
.Case("ios", {"ios", "iOS"})
1079+
.Case("iOS", {"ios", "iOS"})
1080+
.Case("macos", {"macos", "macOS"})
1081+
.Case("macOS", {"macos", "macOS"})
1082+
.Case("tvos", {"tvos", "tvOS"})
1083+
.Case("tvOS", {"tvos", "tvOS"})
1084+
.Case("watchos", {"watchos", "watchOS"})
1085+
.Case("watchOS", {"watchos", "watchOS"})
1086+
.Case("ios_app_extension", {"iOSApplicationExtension", "ios_app_extension"})
1087+
.Case("iOSApplicationExtension", {"iOSApplicationExtension", "ios_app_extension"})
1088+
.Case("macos_app_extension", {"macOSApplicationExtension", "macos_app_extension"})
1089+
.Case("macOSApplicationExtension", {"macOSApplicationExtension", "macos_app_extension"})
1090+
.Case("tvos_app_extension", {"tvOSApplicationExtension", "tvos_app_extension"})
1091+
.Case("tvOSApplicationExtension", {"tvOSApplicationExtension", "tvos_app_extension"})
1092+
.Case("watchos_app_extension", {"watchOSApplicationExtension", "watchos_app_extension"})
1093+
.Case("watchOSApplicationExtension", {"watchOSApplicationExtension", "watchos_app_extension"})
1094+
.Case("maccatalyst", {"macCatalyst", "maccatalyst"})
1095+
.Case("macCatalyst", {"macCatalyst", "maccatalyst"})
1096+
.Case("maccatalyst_app_extension", {"macCatalystApplicationExtension", "maccatalyst_app_extension"})
1097+
.Case("macCatalystApplicationExtension", {"macCatalystApplicationExtension", "maccatalyst_app_extension"})
1098+
.Case("xros", {"visionos", "visionOS", "xros"})
1099+
.Case("visionOS", {"visionos", "visionOS", "xros"})
1100+
.Case("visionos", {"visionos", "visionOS", "xros"})
1101+
.Case("xros_app_extension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
1102+
.Case("visionOSApplicationExtension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
1103+
.Case("visionos_app_extension", {"visionOSApplicationExtension", "visionos_app_extension", "xros_app_extension"})
1104+
.Default({Platform});
1105+
}
10761106
static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
10771107
return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
10781108
.Case("pixel", llvm::Triple::Pixel)

clang/lib/Sema/SemaAvailability.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,22 +488,41 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
488488
// Don't offer a fixit for declarations with availability attributes.
489489
if (Enclosing->hasAttr<AvailabilityAttr>())
490490
return;
491-
if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
491+
Preprocessor &PP = S.getPreprocessor();
492+
if (!PP.isMacroDefined("API_AVAILABLE"))
492493
return;
493494
std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
494495
Enclosing, S.getSourceManager(), S.getLangOpts());
495496
if (!Insertion)
496497
return;
497-
std::string PlatformName =
498-
AvailabilityAttr::getPlatformNameSourceSpelling(
499-
S.getASTContext().getTargetInfo().getPlatformName())
500-
.lower();
498+
StringRef PlatformName =
499+
S.getASTContext().getTargetInfo().getPlatformName();
500+
501+
// Apple's API_AVAILABLE macro expands roughly like this.
502+
// API_AVAILABLE(ios(17.0))
503+
// __attribute__((availability(__API_AVAILABLE_PLATFORM_ios(17.0)))
504+
// __attribute__((availability(ios,introduced=17.0)))
505+
// In order to figure out which platform name to use in the API_AVAILABLE
506+
// macro, the associated __API_AVAILABLE_PLATFORM_ macro needs to be
507+
// found. The __API_AVAILABLE_PLATFORM_ macros aren't consistent about
508+
// using the canonical platform name, source spelling name, or one of the
509+
// other supported names (i.e. one of the keys in canonicalizePlatformName
510+
// that's neither). Check all of the supported names for a match.
511+
std::vector<StringRef> EquivalentPlatforms =
512+
AvailabilityAttr::equivalentPlatformNames(PlatformName);
513+
llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_";
514+
auto AvailablePlatform =
515+
llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) {
516+
return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str());
517+
});
518+
if (AvailablePlatform == EquivalentPlatforms.end())
519+
return;
501520
std::string Introduced =
502521
OffendingDecl->getVersionIntroduced().getAsString();
503522
FixitNoteDiag << FixItHint::CreateInsertion(
504523
Insertion->Loc,
505-
(llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
506-
"(" + Introduced + "))" + Insertion->Suffix)
524+
(llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" +
525+
*AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix)
507526
.str());
508527
}
509528
return;

clang/test/FixIt/fixit-availability-maccatalyst.m

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ int use(void) {
1111
// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:14-[[@LINE-2]]:14}:"\n } else {\n // Fallback on earlier versions\n }"
1212
}
1313

14-
#define API_AVAILABLE(X) __attribute__((availability(macCatalyst, introduced=13.2))) __attribute__((availability(ios, introduced=13.1))) // dummy macro
14+
#define API_AVAILABLE(x) __attribute__((availability(__API_AVAILABLE_PLATFORM_##x)))
15+
#define __API_AVAILABLE_PLATFORM_macCatalyst(x) macCatalyst,introduced=x
1516

16-
API_AVAILABLE(macos(10.12))
17+
API_AVAILABLE(macCatalyst(13.2))
1718
@interface NewClass
1819
@end
1920

2021
@interface OldButOfferFixit
2122
@property(copy) NewClass *prop;
22-
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:1-[[@LINE-2]]:1}:"API_AVAILABLE(maccatalyst(13.2))\n"
23+
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:1-[[@LINE-2]]:1}:"API_AVAILABLE(macCatalyst(13.2))\n"
2324

2425
@end

clang/test/FixIt/fixit-availability.mm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ void wrapDeclStmtUses() {
118118
}
119119
}
120120

121-
#define API_AVAILABLE(X) __attribute__((availability(macos, introduced=10.12))) // dummy macro
121+
#define API_AVAILABLE(x) __attribute__((availability(__API_AVAILABLE_PLATFORM_##x)))
122+
#define __API_AVAILABLE_PLATFORM_macos(x) macos,introduced=x
122123

123124
API_AVAILABLE(macos(10.12))
124125
@interface NewClass

0 commit comments

Comments
 (0)