diff --git a/CMakeLists.txt b/CMakeLists.txt index 484f1899e48a0..7fc20e9133d33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -683,7 +683,11 @@ endif() # # Set up global CMake variables for API notes. # - +# API notes version 1.0.0 +# +# Change the above comment to 'touch' this file and keep incremental builds +# working when adding a new apinotes file. +# set(SWIFT_API_NOTES_PATH "${SWIFT_SOURCE_DIR}/apinotes") if(NOT EXISTS "${SWIFT_API_NOTES_PATH}/Foundation.apinotes") message(FATAL_ERROR "API notes are not available in ${SWIFT_API_NOTES_PATH}") diff --git a/apinotes/CoreGraphics.apinotes b/apinotes/CoreGraphics.apinotes new file mode 100644 index 0000000000000..02a6df19c9ebf --- /dev/null +++ b/apinotes/CoreGraphics.apinotes @@ -0,0 +1,65 @@ +--- +Name: CoreGraphics +SwiftInferImportAsMember: true +# The below are inline functions that are irrelevant due to memberwise inits +Functions: +- Name: CGPointMake + Availability: nonswift +- Name: CGSizeMake + Availability: nonswift +- Name: CGVectorMake + Availability: nonswift +- Name: CGRectMake + Availability: nonswift +- Name: CGAffineTransformMake + Availability: nonswift +# The below are fixups that inference didn't quite do what we wanted, and are +# pulled over from what used to be in the overlays +- Name: CGRectIsNull + SwiftName: "getter:CGRect.isNull(self:)" +- Name: CGRectIsEmpty + SwiftName: "getter:CGRect.isEmpty(self:)" +- Name: CGRectIsInfinite + SwiftName: "getter:CGRect.isInfinite(self:)" +- Name: CGRectStandardize + SwiftName: "getter:CGRect.standardized(self:)" +- Name: CGRectIntegral + SwiftName: "getter:CGRect.integral(self:)" +- Name: CGRectInset + SwiftName: "CGRect.insetBy(self:dx:dy:)" +- Name: CGRectOffset + SwiftName: "CGRect.offsetBy(self:dx:dy:)" +- Name: CGRectUnion + SwiftName: "CGRect.union(self:_:)" +- Name: CGRectIntersection + SwiftName: "CGRect.intersect(self:_:)" +- Name: CGRectContainsRect + SwiftName: "CGRect.contains(self:_:)" +- Name: CGRectContainsPoint + SwiftName: "CGRect.contains(self:_:)" +- Name: CGRectIntersectsRect + SwiftName: "CGRect.intersects(self:_:)" +# The below are left alone, due to an unknown bug +# FIXME: fix me +- Name: CGColorSpaceCreateDeviceRGB + SwiftName: "CGColorSpaceCreateDeviceRGB()" + +# The below are globals that are defined as opaque C constants for no good +# reason. +Globals: +- Name: CGPointZero + Availability: nonswift +- Name: CGSizeZero + Availability: nonswift +- Name: CGVectorZero + Availability: nonswift +- Name: CGRectZero + Availability: nonswift +- Name: CGAffineTransformIdentity + Availability: nonswift +# The below are left alone, due to an unknown bug +# FIXME: fix me +- Name: kCGColorBlack + SwiftName: "kCGColorBlack" +- Name: kCGColorWhite + SwiftName: "kCGColorWhite" diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 926f03f47dfdf..1dae9e38623d8 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2004,6 +2004,36 @@ hasOrInheritsSwiftBridgeAttr(const clang::ObjCInterfaceDecl *objcClass) { return false; } +/// Whether the decl is from a module who requested import-as-member inference +static bool moduleIsInferImportAsMember(const clang::NamedDecl *decl, + clang::Sema &clangSema) { + clang::Module *submodule; + if (auto m = decl->getImportedOwningModule()) { + submodule = m; + } else if (auto m = decl->getLocalOwningModule()) { + submodule = m; + } else if (auto m = clangSema.getPreprocessor().getCurrentModule()) { + submodule = m; + } else if (auto m = clangSema.getPreprocessor().getCurrentSubmodule()) { + submodule = m; + } else { + return false; + } + + while (submodule) { + if (submodule->IsSwiftInferImportAsMember) { + // HACK HACK HACK: This is a workaround for some module invalidation issue + // and inconsistency. This will go away soon. + if (submodule->Name != "CoreGraphics") + return false; + return true; + } + submodule = submodule->Parent; + } + + return false; +} + auto ClangImporter::Implementation::importFullName( const clang::NamedDecl *D, ImportNameOptions options, @@ -2186,7 +2216,8 @@ auto ClangImporter::Implementation::importFullName( return result; } - } else if (InferImportAsMember && + } else if ((InferImportAsMember || + moduleIsInferImportAsMember(D, clangSema)) && (isa(D) || isa(D)) && dc->isTranslationUnit()) { auto inference = IAMResult::infer(SwiftContext, clangSema, D); diff --git a/lib/ClangImporter/IAMInference.cpp b/lib/ClangImporter/IAMInference.cpp index 0468c18abde38..d80c36c7d1832 100644 --- a/lib/ClangImporter/IAMInference.cpp +++ b/lib/ClangImporter/IAMInference.cpp @@ -39,6 +39,8 @@ STATISTIC(FailInferFunction, "# of functions unable to infer"); // Specifically skipped/avoided STATISTIC(SkipLeadingUnderscore, "# of globals skipped due to leading underscore"); +STATISTIC(SkipCFMemoryManagement, + "# of CF memory management globals skipped"); // Success statistics STATISTIC(SuccessImportAsTypeID, "# imported as 'typeID'"); @@ -176,6 +178,7 @@ class IAMInference { } IAMResult infer(const clang::NamedDecl *); + IAMResult inferVar(const clang::VarDecl *); private: // typeID @@ -536,40 +539,42 @@ static bool roughlyEqual(clang::QualType left, clang::QualType right) { right->getUnqualifiedDesugaredType(); } -bool IAMInference::validToImportAsProperty( - const clang::FunctionDecl *originalDecl, StringRef propSpec, - Optional selfIndex, const clang::FunctionDecl *&pairedAccessor) { - bool isGet = propSpec == "Get"; - pairedAccessor = findPairedAccessor(originalDecl->getName(), propSpec); - if (!pairedAccessor) - return isGet; +static bool +isValidAsStaticProperty(const clang::FunctionDecl *getterDecl, + const clang::FunctionDecl *setterDecl = nullptr) { + // Getter has none, setter has one arg + if (getterDecl->getNumParams() != 0 || + (setterDecl && setterDecl->getNumParams() != 1)) { + ++InvalidPropertyStaticNumParams; + return false; + } - auto getterDecl = isGet ? originalDecl : pairedAccessor; - auto setterDecl = isGet ? pairedAccessor : originalDecl; + // Setter's arg type should be same as getter's return type auto getterTy = getterDecl->getReturnType(); - - // See if this is a static property - if (!selfIndex) { - // Getter has none, setter has one arg - if (getterDecl->getNumParams() != 0 || setterDecl->getNumParams() != 1) { - ++InvalidPropertyStaticNumParams; - return false; - } - - // Setter's arg type should be same as getter's return type - if (!roughlyEqual(getterTy, setterDecl->getParamDecl(0)->getType())) { - ++InvalidPropertyStaticGetterSetterType; - return false; - } - - return true; + if (setterDecl && + !roughlyEqual(getterTy, setterDecl->getParamDecl(0)->getType())) { + ++InvalidPropertyStaticGetterSetterType; + return false; } + return true; +} + +static bool +isValidAsInstanceProperty(const clang::FunctionDecl *getterDecl, + const clang::FunctionDecl *setterDecl = nullptr) { // Instance property, look beyond self - if (getterDecl->getNumParams() != 1 || setterDecl->getNumParams() != 2) { + if (getterDecl->getNumParams() != 1 || + (setterDecl && setterDecl->getNumParams() != 2)) { ++InvalidPropertyInstanceNumParams; return false; } + + if (!setterDecl) + return true; + + // Make sure they pair up + auto getterTy = getterDecl->getReturnType(); auto selfTy = getterDecl->getParamDecl(0)->getType(); clang::QualType setterTy = {}; @@ -593,39 +598,65 @@ bool IAMInference::validToImportAsProperty( return true; } -IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { - if (clangDecl->getName().startswith("_")) { - ++SkipLeadingUnderscore; - return {}; +bool IAMInference::validToImportAsProperty( + const clang::FunctionDecl *originalDecl, StringRef propSpec, + Optional selfIndex, const clang::FunctionDecl *&pairedAccessor) { + bool isGet = propSpec == "Get"; + pairedAccessor = findPairedAccessor(originalDecl->getName(), propSpec); + if (!pairedAccessor) { + if (!isGet) + return false; + if (!selfIndex) + return isValidAsStaticProperty(originalDecl); + return isValidAsInstanceProperty(originalDecl); } - if (auto varDecl = dyn_cast(clangDecl)) { - auto fail = [varDecl]() -> IAMResult { - DEBUG(llvm::dbgs() << "failed to infer variable: "); - DEBUG(varDecl->print(llvm::dbgs())); - DEBUG(llvm::dbgs() << "\n"); - ++FailInferVar; - return {}; - }; - - // Try to find a type to add this as a static property to - StringRef workingName = varDecl->getName(); - if (workingName.empty()) - return fail(); + auto getterDecl = isGet ? originalDecl : pairedAccessor; + auto setterDecl = isGet ? pairedAccessor : originalDecl; - // Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with - // property "Baz" - if (*camel_case::getWords(workingName).begin() == "k") - workingName = workingName.drop_front(1); + if (!selfIndex) + return isValidAsStaticProperty(getterDecl, setterDecl); - NameBuffer remainingName; - if (auto effectiveDC = findTypeAndMatch(workingName, remainingName)) + return isValidAsInstanceProperty(getterDecl, setterDecl); +} - return importAsStaticProperty(remainingName, effectiveDC); +IAMResult IAMInference::inferVar(const clang::VarDecl *varDecl) { + auto fail = [varDecl]() -> IAMResult { + DEBUG(llvm::dbgs() << "failed to infer variable: "); + DEBUG(varDecl->print(llvm::dbgs())); + DEBUG(llvm::dbgs() << "\n"); + ++FailInferVar; + return {}; + }; + // Try to find a type to add this as a static property to + StringRef workingName = varDecl->getName(); + if (workingName.empty()) return fail(); + + // Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with + // property "Baz" + if (*camel_case::getWords(workingName).begin() == "k") + workingName = workingName.drop_front(1); + + NameBuffer remainingName; + if (auto effectiveDC = findTypeAndMatch(workingName, remainingName)) + + return importAsStaticProperty(remainingName, effectiveDC); + + return fail(); +} + +IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { + if (clangDecl->getName().startswith("_")) { + ++SkipLeadingUnderscore; + return {}; } + // Try to infer a member variable + if (auto varDecl = dyn_cast(clangDecl)) + return inferVar(varDecl); + // Try to infer a member function auto funcDecl = dyn_cast(clangDecl); if (!funcDecl) { @@ -651,9 +682,11 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { auto retTy = funcDecl->getReturnType(); unsigned numParams = funcDecl->getNumParams(); - // 0) Special cases are specially handled: *GetTypeID() + // 0) Special cases are specially handled // StringRef getTypeID = "GetTypeID"; + StringRef cfSpecials[] = {"Release", "Retain", "Autorelease"}; + // *GetTypeID if (numParams == 0 && workingName.endswith(getTypeID)) { NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch( @@ -664,6 +697,19 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { return importAsTypeID(retTy, effectiveDC); } } + // *Release/*Retain/*Autorelease + } else if (numParams == 1 && + std::any_of(std::begin(cfSpecials), std::end(cfSpecials), + [workingName](StringRef suffix) { + return workingName.endswith(suffix); + })) { + if (auto type = + funcDecl->getParamDecl(0)->getType()->getAs()) { + if (CFPointeeInfo::classifyTypedef(type->getDecl())) { + ++SkipCFMemoryManagement; + return {}; + } + } } // 1) If we find an init specifier and our name matches the return type, we diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index 3f30d96580614..b320b0ed49edc 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -146,7 +146,7 @@ const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1; /// Lookup table minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 11; // globals-as-members +const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 12; // CG import-as-member /// A lookup table that maps Swift names to the set of Clang /// declarations with that particular name. diff --git a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift index 44400793c55d2..229f4894006ad 100644 --- a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift +++ b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift @@ -130,14 +130,6 @@ public extension CGRect { @_transparent // @fragile get { return CGRect(x: 0, y: 0, width: 0, height: 0) } } - static var null: CGRect { - @_transparent // @fragile - get { return CGRectNull } - } - static var infinite: CGRect { - @_transparent // @fragile - get { return CGRectInfinite } - } @_transparent // @fragile init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) { @@ -157,61 +149,6 @@ public extension CGRect { size: CGSize(width: width, height: height)) } - var width: CGFloat { - @_transparent // @fragile - get { return CGRectGetWidth(self) } - } - var height: CGFloat { - @_transparent // @fragile - get { return CGRectGetHeight(self) } - } - - var minX: CGFloat { - @_transparent // @fragile - get { return CGRectGetMinX(self) } - } - var midX: CGFloat { - @_transparent // @fragile - get { return CGRectGetMidX(self) } - } - var maxX: CGFloat { - @_transparent // @fragile - get { return CGRectGetMaxX(self) } - } - var minY: CGFloat { - @_transparent // @fragile - get { return CGRectGetMinY(self) } - } - var midY: CGFloat { - @_transparent // @fragile - get { return CGRectGetMidY(self) } - } - var maxY: CGFloat { - @_transparent // @fragile - get { return CGRectGetMaxY(self) } - } - var isNull: Bool { - @_transparent // @fragile - get { return CGRectIsNull(self) } - } - var isEmpty: Bool { - @_transparent // @fragile - get { return CGRectIsEmpty(self) } - } - var isInfinite: Bool { - @_transparent // @fragile - get { return CGRectIsInfinite(self) } - } - var standardized: CGRect { - @_transparent // @fragile - get { return CGRectStandardize(self) } - } - - var integral: CGRect { - @_transparent // @fragile - get { return CGRectIntegral(self) } - } - @_transparent // @fragile mutating func standardizeInPlace() { self = standardized @@ -222,45 +159,21 @@ public extension CGRect { self = integral } - @_transparent // @fragile - @warn_unused_result(mutable_variant: "insetInPlace") - func insetBy(dx dx: CGFloat, dy: CGFloat) -> CGRect { - return CGRectInset(self, dx, dy) - } - @_transparent // @fragile mutating func insetInPlace(dx dx: CGFloat, dy: CGFloat) { self = insetBy(dx: dx, dy: dy) } - @_transparent // @fragile - @warn_unused_result(mutable_variant: "offsetInPlace") - func offsetBy(dx dx: CGFloat, dy: CGFloat) -> CGRect { - return CGRectOffset(self, dx, dy) - } - @_transparent // @fragile mutating func offsetInPlace(dx dx: CGFloat, dy: CGFloat) { self = offsetBy(dx: dx, dy: dy) } - @_transparent // @fragile - @warn_unused_result(mutable_variant: "unionInPlace") - func union(rect: CGRect) -> CGRect { - return CGRectUnion(self, rect) - } - @_transparent // @fragile mutating func unionInPlace(rect: CGRect) { self = union(rect) } - @_transparent // @fragile - @warn_unused_result(mutable_variant: "intersectInPlace") - func intersect(rect: CGRect) -> CGRect { - return CGRectIntersection(self, rect) - } - @_transparent // @fragile mutating func intersectInPlace(rect: CGRect) { self = intersect(rect) @@ -273,27 +186,10 @@ public extension CGRect { { var slice = CGRect.zero var remainder = CGRect.zero - CGRectDivide(self, &slice, &remainder, atDistance, fromEdge) + divide(slice: &slice, remainder: &remainder, amount: atDistance, + edge: fromEdge) return (slice, remainder) } - - @_transparent // @fragile - @warn_unused_result - func contains(rect: CGRect) -> Bool { - return CGRectContainsRect(self, rect) - } - - @_transparent // @fragile - @warn_unused_result - func contains(point: CGPoint) -> Bool { - return CGRectContainsPoint(self, point) - } - - @_transparent // @fragile - @warn_unused_result - func intersects(rect: CGRect) -> Bool { - return CGRectIntersectsRect(self, rect) - } } extension CGRect : CustomReflectable, CustomPlaygroundQuickLookable { @@ -321,28 +217,13 @@ extension CGRect : Equatable {} @_transparent // @fragile @warn_unused_result public func == (lhs: CGRect, rhs: CGRect) -> Bool { - return CGRectEqualToRect(lhs, rhs) -} - -// Overlay the C names of these constants with transparent definitions. The -// C constants are opaque extern globals for no good reason. - -public var CGPointZero: CGPoint { - @_transparent // @fragile - get { return CGPoint.zero } -} - -public var CGRectZero: CGRect { - @_transparent // @fragile - get { return CGRect.zero } + return lhs.equalToRect(rect2: rhs) } -public var CGSizeZero: CGSize { - @_transparent // @fragile - get { return CGSize.zero } +extension CGAffineTransform { + public static var identity: CGAffineTransform { + @_transparent // @fragile + get { return CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0) } + } } -public var CGAffineTransformIdentity: CGAffineTransform { - @_transparent // @fragile - get { return CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0) } -} diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift index 47a0c2032968c..d71bd4fc5cc6d 100644 --- a/stdlib/public/SDK/UIKit/UIKit.swift +++ b/stdlib/public/SDK/UIKit/UIKit.swift @@ -204,7 +204,7 @@ extension UIView : CustomPlaygroundQuickLookable { // be present.) let ctx: CGContext! = UIGraphicsGetCurrentContext() UIColor(white:1.0, alpha:0.0).set() - CGContextFillRect(ctx, bounds) + ctx.fillRect(bounds) layer.render(in: ctx) let image: UIImage! = UIGraphicsGetImageFromCurrentImageContext() diff --git a/test/IDE/infer_import_as_member.swift b/test/IDE/infer_import_as_member.swift index f5f2000051160..675dc8b5e7829 100644 --- a/test/IDE/infer_import_as_member.swift +++ b/test/IDE/infer_import_as_member.swift @@ -48,6 +48,7 @@ import InferImportAsMember // PRINT-LABEL: /// Various static functions that can't quite be imported as properties. // PRINT-NEXT: static func staticGetNonPropertyNumParams() -> Float // PRINT-NEXT: static func staticSetNonPropertyNumParams(a a: Float, b b: Float) +// PRINT-NEXT: static func staticGetNonPropertyNumParamsGetter(d d: Double) // PRINT-NEXT: static func staticGetNonPropertyType() -> Float // PRINT-NEXT: static func staticSetNonPropertyType(x x: Double) // PRINT-NEXT: static func staticGetNonPropertyNoSelf() -> Float diff --git a/test/Interpreter/SDK/CALayer.swift b/test/Interpreter/SDK/CALayer.swift index 8dd183ba49447..f91a52e231c80 100644 --- a/test/Interpreter/SDK/CALayer.swift +++ b/test/Interpreter/SDK/CALayer.swift @@ -22,10 +22,10 @@ func hangCanary(o: AnyObject) { class FooLayer: CALayer { var black: CGColor - var white: CGColor = CGColorGetConstantColor(kCGColorWhite)! + var white: CGColor = CGColor.getConstantColor(colorName: kCGColorWhite)! override init() { - black = CGColorGetConstantColor(kCGColorBlack)! + black = CGColor.getConstantColor(colorName: kCGColorBlack)! super.init() hangCanary(self) } diff --git a/test/Interpreter/SDK/c_pointers.swift b/test/Interpreter/SDK/c_pointers.swift index 0fb4824d6277f..b12f550b4ec8c 100644 --- a/test/Interpreter/SDK/c_pointers.swift +++ b/test/Interpreter/SDK/c_pointers.swift @@ -23,7 +23,7 @@ typealias XXColor = UIColor // let rgb = CGColorSpaceCreateDeviceRGB() -let cgRed = CGColorCreate(rgb, [1.0, 0.0, 0.0, 1.0])! +let cgRed = CGColor(space: rgb, components: [1.0, 0.0, 0.0, 1.0])! let nsRed = XXColor(cgColor: cgRed) diff --git a/test/Interpreter/SDK/cf_extensions.swift b/test/Interpreter/SDK/cf_extensions.swift index e20b921657829..03f50b06d971e 100644 --- a/test/Interpreter/SDK/cf_extensions.swift +++ b/test/Interpreter/SDK/cf_extensions.swift @@ -22,12 +22,12 @@ extension CGColorSpace { extension CGColor { class func create(colorSpace colorSpace: CGColorSpace, components: [CGFloat]) -> CGColor { - return CGColorCreate(colorSpace, components)! + return CGColor(space: colorSpace, components: components)! } - var r: CGFloat { return CGColorGetComponents(self)[0] } - var g: CGFloat { return CGColorGetComponents(self)[1] } - var b: CGFloat { return CGColorGetComponents(self)[2] } + var r: CGFloat { return components[0] } + var g: CGFloat { return components[1] } + var b: CGFloat { return components[2] } } let pink = CGColor.create(colorSpace: .deviceRGB(), diff --git a/test/Interpreter/SDK/cf_type_bridging.swift b/test/Interpreter/SDK/cf_type_bridging.swift index 655439a7281e7..e0f32168478e6 100644 --- a/test/Interpreter/SDK/cf_type_bridging.swift +++ b/test/Interpreter/SDK/cf_type_bridging.swift @@ -10,7 +10,8 @@ import AppKit import UIKit #endif -let foo: [CGColor] = [CGColorCreate(CGColorSpaceCreateDeviceRGB(), [1.0, 0.0, 0.0, 1.0])!] +let foo: [CGColor] = [CGColor(space: CGColorSpaceCreateDeviceRGB(), + components: [1.0, 0.0, 0.0, 1.0])!] let bar = foo as NSArray