Skip to content

Commit b0d54b1

Browse files
committed
Merge pull request swiftlang#2071 from milseman/coregraphics
[Import as member] Core Graphics
2 parents 5d34f66 + 13c2a34 commit b0d54b1

12 files changed

+219
-190
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,11 @@ endif()
683683
#
684684
# Set up global CMake variables for API notes.
685685
#
686-
686+
# API notes version 1.0.0
687+
#
688+
# Change the above comment to 'touch' this file and keep incremental builds
689+
# working when adding a new apinotes file.
690+
#
687691
set(SWIFT_API_NOTES_PATH "${SWIFT_SOURCE_DIR}/apinotes")
688692
if(NOT EXISTS "${SWIFT_API_NOTES_PATH}/Foundation.apinotes")
689693
message(FATAL_ERROR "API notes are not available in ${SWIFT_API_NOTES_PATH}")

apinotes/CoreGraphics.apinotes

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
Name: CoreGraphics
3+
SwiftInferImportAsMember: true
4+
# The below are inline functions that are irrelevant due to memberwise inits
5+
Functions:
6+
- Name: CGPointMake
7+
Availability: nonswift
8+
- Name: CGSizeMake
9+
Availability: nonswift
10+
- Name: CGVectorMake
11+
Availability: nonswift
12+
- Name: CGRectMake
13+
Availability: nonswift
14+
- Name: CGAffineTransformMake
15+
Availability: nonswift
16+
# The below are fixups that inference didn't quite do what we wanted, and are
17+
# pulled over from what used to be in the overlays
18+
- Name: CGRectIsNull
19+
SwiftName: "getter:CGRect.isNull(self:)"
20+
- Name: CGRectIsEmpty
21+
SwiftName: "getter:CGRect.isEmpty(self:)"
22+
- Name: CGRectIsInfinite
23+
SwiftName: "getter:CGRect.isInfinite(self:)"
24+
- Name: CGRectStandardize
25+
SwiftName: "getter:CGRect.standardized(self:)"
26+
- Name: CGRectIntegral
27+
SwiftName: "getter:CGRect.integral(self:)"
28+
- Name: CGRectInset
29+
SwiftName: "CGRect.insetBy(self:dx:dy:)"
30+
- Name: CGRectOffset
31+
SwiftName: "CGRect.offsetBy(self:dx:dy:)"
32+
- Name: CGRectUnion
33+
SwiftName: "CGRect.union(self:_:)"
34+
- Name: CGRectIntersection
35+
SwiftName: "CGRect.intersect(self:_:)"
36+
- Name: CGRectContainsRect
37+
SwiftName: "CGRect.contains(self:_:)"
38+
- Name: CGRectContainsPoint
39+
SwiftName: "CGRect.contains(self:_:)"
40+
- Name: CGRectIntersectsRect
41+
SwiftName: "CGRect.intersects(self:_:)"
42+
# The below are left alone, due to an unknown bug
43+
# FIXME: fix me
44+
- Name: CGColorSpaceCreateDeviceRGB
45+
SwiftName: "CGColorSpaceCreateDeviceRGB()"
46+
47+
# The below are globals that are defined as opaque C constants for no good
48+
# reason.
49+
Globals:
50+
- Name: CGPointZero
51+
Availability: nonswift
52+
- Name: CGSizeZero
53+
Availability: nonswift
54+
- Name: CGVectorZero
55+
Availability: nonswift
56+
- Name: CGRectZero
57+
Availability: nonswift
58+
- Name: CGAffineTransformIdentity
59+
Availability: nonswift
60+
# The below are left alone, due to an unknown bug
61+
# FIXME: fix me
62+
- Name: kCGColorBlack
63+
SwiftName: "kCGColorBlack"
64+
- Name: kCGColorWhite
65+
SwiftName: "kCGColorWhite"

lib/ClangImporter/ClangImporter.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,6 +2004,36 @@ hasOrInheritsSwiftBridgeAttr(const clang::ObjCInterfaceDecl *objcClass) {
20042004
return false;
20052005
}
20062006

2007+
/// Whether the decl is from a module who requested import-as-member inference
2008+
static bool moduleIsInferImportAsMember(const clang::NamedDecl *decl,
2009+
clang::Sema &clangSema) {
2010+
clang::Module *submodule;
2011+
if (auto m = decl->getImportedOwningModule()) {
2012+
submodule = m;
2013+
} else if (auto m = decl->getLocalOwningModule()) {
2014+
submodule = m;
2015+
} else if (auto m = clangSema.getPreprocessor().getCurrentModule()) {
2016+
submodule = m;
2017+
} else if (auto m = clangSema.getPreprocessor().getCurrentSubmodule()) {
2018+
submodule = m;
2019+
} else {
2020+
return false;
2021+
}
2022+
2023+
while (submodule) {
2024+
if (submodule->IsSwiftInferImportAsMember) {
2025+
// HACK HACK HACK: This is a workaround for some module invalidation issue
2026+
// and inconsistency. This will go away soon.
2027+
if (submodule->Name != "CoreGraphics")
2028+
return false;
2029+
return true;
2030+
}
2031+
submodule = submodule->Parent;
2032+
}
2033+
2034+
return false;
2035+
}
2036+
20072037
auto ClangImporter::Implementation::importFullName(
20082038
const clang::NamedDecl *D,
20092039
ImportNameOptions options,
@@ -2186,7 +2216,8 @@ auto ClangImporter::Implementation::importFullName(
21862216

21872217
return result;
21882218
}
2189-
} else if (InferImportAsMember &&
2219+
} else if ((InferImportAsMember ||
2220+
moduleIsInferImportAsMember(D, clangSema)) &&
21902221
(isa<clang::VarDecl>(D) || isa<clang::FunctionDecl>(D)) &&
21912222
dc->isTranslationUnit()) {
21922223
auto inference = IAMResult::infer(SwiftContext, clangSema, D);

lib/ClangImporter/IAMInference.cpp

Lines changed: 97 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ STATISTIC(FailInferFunction, "# of functions unable to infer");
3939
// Specifically skipped/avoided
4040
STATISTIC(SkipLeadingUnderscore,
4141
"# of globals skipped due to leading underscore");
42+
STATISTIC(SkipCFMemoryManagement,
43+
"# of CF memory management globals skipped");
4244

4345
// Success statistics
4446
STATISTIC(SuccessImportAsTypeID, "# imported as 'typeID'");
@@ -176,6 +178,7 @@ class IAMInference {
176178
}
177179

178180
IAMResult infer(const clang::NamedDecl *);
181+
IAMResult inferVar(const clang::VarDecl *);
179182

180183
private:
181184
// typeID
@@ -536,40 +539,42 @@ static bool roughlyEqual(clang::QualType left, clang::QualType right) {
536539
right->getUnqualifiedDesugaredType();
537540
}
538541

539-
bool IAMInference::validToImportAsProperty(
540-
const clang::FunctionDecl *originalDecl, StringRef propSpec,
541-
Optional<unsigned> selfIndex, const clang::FunctionDecl *&pairedAccessor) {
542-
bool isGet = propSpec == "Get";
543-
pairedAccessor = findPairedAccessor(originalDecl->getName(), propSpec);
544-
if (!pairedAccessor)
545-
return isGet;
542+
static bool
543+
isValidAsStaticProperty(const clang::FunctionDecl *getterDecl,
544+
const clang::FunctionDecl *setterDecl = nullptr) {
545+
// Getter has none, setter has one arg
546+
if (getterDecl->getNumParams() != 0 ||
547+
(setterDecl && setterDecl->getNumParams() != 1)) {
548+
++InvalidPropertyStaticNumParams;
549+
return false;
550+
}
546551

547-
auto getterDecl = isGet ? originalDecl : pairedAccessor;
548-
auto setterDecl = isGet ? pairedAccessor : originalDecl;
552+
// Setter's arg type should be same as getter's return type
549553
auto getterTy = getterDecl->getReturnType();
550-
551-
// See if this is a static property
552-
if (!selfIndex) {
553-
// Getter has none, setter has one arg
554-
if (getterDecl->getNumParams() != 0 || setterDecl->getNumParams() != 1) {
555-
++InvalidPropertyStaticNumParams;
556-
return false;
557-
}
558-
559-
// Setter's arg type should be same as getter's return type
560-
if (!roughlyEqual(getterTy, setterDecl->getParamDecl(0)->getType())) {
561-
++InvalidPropertyStaticGetterSetterType;
562-
return false;
563-
}
564-
565-
return true;
554+
if (setterDecl &&
555+
!roughlyEqual(getterTy, setterDecl->getParamDecl(0)->getType())) {
556+
++InvalidPropertyStaticGetterSetterType;
557+
return false;
566558
}
567559

560+
return true;
561+
}
562+
563+
static bool
564+
isValidAsInstanceProperty(const clang::FunctionDecl *getterDecl,
565+
const clang::FunctionDecl *setterDecl = nullptr) {
568566
// Instance property, look beyond self
569-
if (getterDecl->getNumParams() != 1 || setterDecl->getNumParams() != 2) {
567+
if (getterDecl->getNumParams() != 1 ||
568+
(setterDecl && setterDecl->getNumParams() != 2)) {
570569
++InvalidPropertyInstanceNumParams;
571570
return false;
572571
}
572+
573+
if (!setterDecl)
574+
return true;
575+
576+
// Make sure they pair up
577+
auto getterTy = getterDecl->getReturnType();
573578
auto selfTy = getterDecl->getParamDecl(0)->getType();
574579

575580
clang::QualType setterTy = {};
@@ -593,39 +598,65 @@ bool IAMInference::validToImportAsProperty(
593598
return true;
594599
}
595600

596-
IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
597-
if (clangDecl->getName().startswith("_")) {
598-
++SkipLeadingUnderscore;
599-
return {};
601+
bool IAMInference::validToImportAsProperty(
602+
const clang::FunctionDecl *originalDecl, StringRef propSpec,
603+
Optional<unsigned> selfIndex, const clang::FunctionDecl *&pairedAccessor) {
604+
bool isGet = propSpec == "Get";
605+
pairedAccessor = findPairedAccessor(originalDecl->getName(), propSpec);
606+
if (!pairedAccessor) {
607+
if (!isGet)
608+
return false;
609+
if (!selfIndex)
610+
return isValidAsStaticProperty(originalDecl);
611+
return isValidAsInstanceProperty(originalDecl);
600612
}
601613

602-
if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl)) {
603-
auto fail = [varDecl]() -> IAMResult {
604-
DEBUG(llvm::dbgs() << "failed to infer variable: ");
605-
DEBUG(varDecl->print(llvm::dbgs()));
606-
DEBUG(llvm::dbgs() << "\n");
607-
++FailInferVar;
608-
return {};
609-
};
610-
611-
// Try to find a type to add this as a static property to
612-
StringRef workingName = varDecl->getName();
613-
if (workingName.empty())
614-
return fail();
614+
auto getterDecl = isGet ? originalDecl : pairedAccessor;
615+
auto setterDecl = isGet ? pairedAccessor : originalDecl;
615616

616-
// Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with
617-
// property "Baz"
618-
if (*camel_case::getWords(workingName).begin() == "k")
619-
workingName = workingName.drop_front(1);
617+
if (!selfIndex)
618+
return isValidAsStaticProperty(getterDecl, setterDecl);
620619

621-
NameBuffer remainingName;
622-
if (auto effectiveDC = findTypeAndMatch(workingName, remainingName))
620+
return isValidAsInstanceProperty(getterDecl, setterDecl);
621+
}
623622

624-
return importAsStaticProperty(remainingName, effectiveDC);
623+
IAMResult IAMInference::inferVar(const clang::VarDecl *varDecl) {
624+
auto fail = [varDecl]() -> IAMResult {
625+
DEBUG(llvm::dbgs() << "failed to infer variable: ");
626+
DEBUG(varDecl->print(llvm::dbgs()));
627+
DEBUG(llvm::dbgs() << "\n");
628+
++FailInferVar;
629+
return {};
630+
};
625631

632+
// Try to find a type to add this as a static property to
633+
StringRef workingName = varDecl->getName();
634+
if (workingName.empty())
626635
return fail();
636+
637+
// Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with
638+
// property "Baz"
639+
if (*camel_case::getWords(workingName).begin() == "k")
640+
workingName = workingName.drop_front(1);
641+
642+
NameBuffer remainingName;
643+
if (auto effectiveDC = findTypeAndMatch(workingName, remainingName))
644+
645+
return importAsStaticProperty(remainingName, effectiveDC);
646+
647+
return fail();
648+
}
649+
650+
IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
651+
if (clangDecl->getName().startswith("_")) {
652+
++SkipLeadingUnderscore;
653+
return {};
627654
}
628655

656+
// Try to infer a member variable
657+
if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl))
658+
return inferVar(varDecl);
659+
629660
// Try to infer a member function
630661
auto funcDecl = dyn_cast<clang::FunctionDecl>(clangDecl);
631662
if (!funcDecl) {
@@ -651,9 +682,11 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
651682
auto retTy = funcDecl->getReturnType();
652683
unsigned numParams = funcDecl->getNumParams();
653684

654-
// 0) Special cases are specially handled: *GetTypeID()
685+
// 0) Special cases are specially handled
655686
//
656687
StringRef getTypeID = "GetTypeID";
688+
StringRef cfSpecials[] = {"Release", "Retain", "Autorelease"};
689+
// *GetTypeID
657690
if (numParams == 0 && workingName.endswith(getTypeID)) {
658691
NameBuffer remainingName;
659692
if (auto effectiveDC = findTypeAndMatch(
@@ -664,6 +697,19 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
664697
return importAsTypeID(retTy, effectiveDC);
665698
}
666699
}
700+
// *Release/*Retain/*Autorelease
701+
} else if (numParams == 1 &&
702+
std::any_of(std::begin(cfSpecials), std::end(cfSpecials),
703+
[workingName](StringRef suffix) {
704+
return workingName.endswith(suffix);
705+
})) {
706+
if (auto type =
707+
funcDecl->getParamDecl(0)->getType()->getAs<clang::TypedefType>()) {
708+
if (CFPointeeInfo::classifyTypedef(type->getDecl())) {
709+
++SkipCFMemoryManagement;
710+
return {};
711+
}
712+
}
667713
}
668714

669715
// 1) If we find an init specifier and our name matches the return type, we

lib/ClangImporter/SwiftLookupTable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1;
146146
/// Lookup table minor version number.
147147
///
148148
/// When the format changes IN ANY WAY, this number should be incremented.
149-
const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 11; // globals-as-members
149+
const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 12; // CG import-as-member
150150

151151
/// A lookup table that maps Swift names to the set of Clang
152152
/// declarations with that particular name.

0 commit comments

Comments
 (0)