diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 242f0750d432a..c0881c9c9294f 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -260,8 +260,7 @@ class ClangImporter final : public ClangModuleLoader { /// The return value may be an empty identifier, in which case the enum would /// not be imported. /// - /// This is mostly an implementation detail of the importer, but is also - /// used by the debugger. + /// This is not used by the importer itself, but is used by the debugger. Identifier getEnumConstantName(const clang::EnumConstantDecl *enumConstant); /// Writes the mangled name of \p clangDecl to \p os. diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 7716f53bd93da..09b43dc9bc740 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2738,17 +2738,51 @@ void ClangImporter::Implementation::lookupValue( } } - // If we have a declaration and nothing matched so far, try the Swift 2 - // name. + // If we have a declaration and nothing matched so far, try the names used + // in other versions of Swift. if (!anyMatching) { if (auto clangDecl = entry.dyn_cast()) { - if (auto swift2Decl = cast_or_null(importDeclReal( - clangDecl->getMostRecentDecl(), ImportNameVersion::Swift2))) { - if (swift2Decl->getFullName().matchesRef(name) && - swift2Decl->getDeclContext()->isModuleScopeContext()) { - consumer.foundDecl(swift2Decl, + const clang::NamedDecl *recentClangDecl = + clangDecl->getMostRecentDecl(); + auto tryImport = [&](ImportNameVersion nameVersion) -> bool { + // Check to see if the name and context match what we expect. + ImportedName newName = importFullName(recentClangDecl, nameVersion); + if (!newName.getDeclName().matchesRef(name)) + return false; + + const clang::DeclContext *clangDC = + newName.getEffectiveContext().getAsDeclContext(); + if (!clangDC || !clangDC->isFileContext()) + return false; + + // Then try to import the decl under the alternate name. + auto alternateNamedDecl = + cast_or_null(importDeclReal(recentClangDecl, + nameVersion)); + if (!alternateNamedDecl) + return false; + assert(alternateNamedDecl->getFullName().matchesRef(name) && + "importFullName behaved differently from importDecl"); + if (alternateNamedDecl->getDeclContext()->isModuleScopeContext()) { + consumer.foundDecl(alternateNamedDecl, DeclVisibilityKind::VisibleAtTopLevel); + return true; } + return false; + }; + + // Try importing previous versions of the decl first... + ImportNameVersion nameVersion = CurrentVersion; + while (!anyMatching && nameVersion != ImportNameVersion::Raw) { + --nameVersion; + anyMatching = tryImport(nameVersion); + } + // ...then move on to newer versions if none of the old versions + // matched. + nameVersion = CurrentVersion; + while (!anyMatching && nameVersion != ImportNameVersion::LAST_VERSION) { + ++nameVersion; + anyMatching = tryImport(nameVersion); } } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 0b102b55d2eb5..01fa9e0ab4a61 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2009,18 +2009,43 @@ namespace { /*fullyQualified=*/correctSwiftName.importAsMember(), os); } - auto attr = AvailableAttr::createPlatformAgnostic( - ctx, StringRef(), ctx.AllocateCopy(renamed.str()), - PlatformAgnosticAvailabilityKind::SwiftVersionSpecific, - clang::VersionTuple(3)); + unsigned majorVersion = majorVersionNumberForNameVersion(getVersion()); + DeclAttribute *attr; + if (isActiveSwiftVersion() || getVersion() == ImportNameVersion::Raw) { + // "Raw" is the Objective-C name, which was never available in Swift. + // Variants within the active version are usually declarations that + // have been superseded, like the accessors of a property. + attr = AvailableAttr::createPlatformAgnostic( + ctx, /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()), + PlatformAgnosticAvailabilityKind::UnavailableInSwift); + } else if (getVersion() < getActiveSwiftVersion()) { + // A Swift 2 name, for example, was obsoleted in Swift 3. + attr = AvailableAttr::createPlatformAgnostic( + ctx, /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()), + PlatformAgnosticAvailabilityKind::SwiftVersionSpecific, + clang::VersionTuple(majorVersion + 1)); + } else { + // Future names are introduced in their future version. + assert(getVersion() > getActiveSwiftVersion()); + attr = new (ctx) AvailableAttr( + SourceLoc(), SourceRange(), PlatformKind::none, + /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()), + /*Introduced*/clang::VersionTuple(majorVersion), SourceRange(), + /*Deprecated*/clang::VersionTuple(), SourceRange(), + /*Obsoleted*/clang::VersionTuple(), SourceRange(), + PlatformAgnosticAvailabilityKind::SwiftVersionSpecific, + /*Implicit*/true); + } + decl->getAttrs().add(attr); decl->setImplicit(); } - /// Create a typealias for the Swift 2 name of a Clang type declaration. - Decl *importSwift2TypeAlias(const clang::NamedDecl *decl, - ImportedName swift2Name, - ImportedName correctSwiftName); + /// Create a typealias for the name of a Clang type declaration in an + /// alternate version of Swift. + Decl *importCompatibilityTypeAlias(const clang::NamedDecl *decl, + ImportedName compatibilityName, + ImportedName correctSwiftName); /// Create a swift_newtype struct corresponding to a typedef. Returns /// nullptr if unable. @@ -2038,7 +2063,8 @@ namespace { // If we've been asked to produce a Swift 2 stub, handle it via a // typealias. if (correctSwiftName) - return importSwift2TypeAlias(Decl, importedName, *correctSwiftName); + return importCompatibilityTypeAlias(Decl, importedName, + *correctSwiftName); Type SwiftType; if (Decl->getDeclContext()->getRedeclContext()->isTranslationUnit()) { @@ -2253,7 +2279,8 @@ namespace { // If we've been asked to produce a Swift 2 stub, handle it via a // typealias. if (correctSwiftName) - return importSwift2TypeAlias(decl, importedName, *correctSwiftName); + return importCompatibilityTypeAlias(decl, importedName, + *correctSwiftName); auto dc = Impl.importDeclContextOf(decl, importedName.getEffectiveContext()); @@ -2669,7 +2696,8 @@ namespace { // If we've been asked to produce a Swift 2 stub, handle it via a // typealias. if (correctSwiftName) - return importSwift2TypeAlias(decl, importedName, *correctSwiftName); + return importCompatibilityTypeAlias(decl, importedName, + *correctSwiftName); auto dc = Impl.importDeclContextOf(decl, importedName.getEffectiveContext()); @@ -3485,31 +3513,12 @@ namespace { {decl->param_begin(), decl->param_size()}, decl->isVariadic(), redundant); - // Directly ask the NameImporter for the non-init variant of the Swift 2 - // name. - auto rawName = Impl.importFullName(decl, ImportNameVersion::Raw); - if (!rawName) - return result; - - auto rawDecl = importNonInitObjCMethodDecl(decl, dc, rawName, selector, - forceClassMethod); - if (!rawDecl) - return result; - - // Mark the raw imported class method "unavailable", with a useful error - // message. - llvm::SmallString<64> message; - llvm::raw_svector_ostream os(message); - os << "use object construction '" << decl->getClassInterface()->getName() - << "("; - for (auto arg : importedName.getDeclName().getArgumentNames()) { - os << arg << ":"; + if (auto rawDecl = Impl.importDecl(decl, ImportNameVersion::Raw)) { + // We expect the raw decl to always be a method. + assert(isa(rawDecl)); + Impl.addAlternateDecl(result, cast(rawDecl)); } - os << ")'"; - rawDecl->getAttrs().add(AvailableAttr::createPlatformAgnostic( - Impl.SwiftContext, Impl.SwiftContext.AllocateCopy(os.str()))); - markAsVariant(rawDecl, importedName); - Impl.addAlternateDecl(result, cast(rawDecl)); + return result; } @@ -3952,7 +3961,8 @@ namespace { // If we've been asked to produce a Swift 2 stub, handle it via a // typealias. if (correctSwiftName) - return importSwift2TypeAlias(decl, importedName, *correctSwiftName); + return importCompatibilityTypeAlias(decl, importedName, + *correctSwiftName); Identifier name = importedName.getDeclName().getBaseName(); @@ -4087,7 +4097,8 @@ namespace { // If we've been asked to produce a Swift 2 stub, handle it via a // typealias. if (correctSwiftName) - return importSwift2TypeAlias(decl, importedName, *correctSwiftName); + return importCompatibilityTypeAlias(decl, importedName, + *correctSwiftName); auto name = importedName.getDeclName().getBaseName(); @@ -4625,9 +4636,10 @@ SwiftDeclConverter::importCFClassType(const clang::TypedefNameDecl *decl, return theClass; } -Decl *SwiftDeclConverter::importSwift2TypeAlias(const clang::NamedDecl *decl, - ImportedName swift2Name, - ImportedName correctSwiftName) { +Decl *SwiftDeclConverter::importCompatibilityTypeAlias( + const clang::NamedDecl *decl, + ImportedName compatibilityName, + ImportedName correctSwiftName) { // Import the referenced declaration. If it doesn't come in as a type, // we don't care. auto importedDecl = Impl.importDecl(decl, getActiveSwiftVersion()); @@ -4660,19 +4672,14 @@ Decl *SwiftDeclConverter::importSwift2TypeAlias(const clang::NamedDecl *decl, // Create the type alias. auto alias = Impl.createDeclWithClangNode( - decl, - Accessibility::Public, Impl.importSourceLoc(decl->getLocStart()), - SourceLoc(), swift2Name.getDeclName().getBaseName(), - Impl.importSourceLoc(decl->getLocation()), - genericParams, dc); + decl, Accessibility::Public, Impl.importSourceLoc(decl->getLocStart()), + SourceLoc(), compatibilityName.getDeclName().getBaseName(), + Impl.importSourceLoc(decl->getLocation()), genericParams, dc); alias->setUnderlyingType(underlyingType); alias->setGenericEnvironment(genericEnv); - // Record that this is the Swift 2 version of this declaration. - Impl.ImportedDecls[{decl->getCanonicalDecl(), ImportNameVersion::Swift2}] = - alias; - - // Mark it as the Swift 2 variant. + // Record that this is the official version of this declaration. + Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = alias; markAsVariant(alias, correctSwiftName); return alias; } @@ -6511,7 +6518,7 @@ getSwiftNameFromClangName(StringRef replacement) { if (!clangDecl) return ""; - auto importedName = importFullName(clangDecl, ImportNameVersion::Swift3); + auto importedName = importFullName(clangDecl, CurrentVersion); if (!importedName) return ""; @@ -6753,7 +6760,7 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl, Result = converter.Visit(ClangDecl); HadForwardDeclaration = converter.hadForwardDeclaration(); } - if (!Result && version > ImportNameVersion::Swift2) { + if (!Result && version == CurrentVersion) { // If we couldn't import this Objective-C entity, determine // whether it was a required member of a protocol. bool hasMissingRequiredMember = false; @@ -7563,7 +7570,7 @@ ClangImporter::Implementation::getSpecialTypedefKind(clang::TypedefNameDecl *dec Identifier ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){ - return Impl.importFullName(enumConstant, ImportNameVersion::Swift3) + return Impl.importFullName(enumConstant, Impl.CurrentVersion) .getDeclName() .getBaseName(); } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 8a3f2c8d0daa8..b00f41f201c7d 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -68,6 +68,20 @@ importer::nameVersionFromOptions(const LangOptions &langOpts) { } } +unsigned importer::majorVersionNumberForNameVersion(ImportNameVersion version) { + switch (version) { + case ImportNameVersion::Raw: + return 0; + case ImportNameVersion::Swift2: + return 2; + case ImportNameVersion::Swift3: + return 3; + case ImportNameVersion::Swift4: + return 4; + } +} + + /// Determine whether the given Clang selector matches the given /// selector pieces. static bool isNonNullarySelector(clang::Selector selector, @@ -560,12 +574,90 @@ determineCtorInitializerKind(const clang::ObjCMethodDecl *method) { return None; } +template +static bool matchesVersion(A *versionedAttr, ImportNameVersion version) { + clang::VersionTuple attrVersion = versionedAttr->getVersion(); + if (attrVersion.empty()) + return version == ImportNameVersion::LAST_VERSION; + return attrVersion.getMajor() == majorVersionNumberForNameVersion(version); +} + +const clang::SwiftNameAttr * +importer::findSwiftNameAttr(const clang::Decl *decl, + ImportNameVersion version) { + if (version == ImportNameVersion::Raw) + return nullptr; + + // Handle versioned API notes for Swift 3 and later. This is the common case. + if (version != ImportNameVersion::Swift2) { + for (auto *attr : decl->attrs()) { + if (auto *versionedAttr = dyn_cast(attr)) { + if (!matchesVersion(versionedAttr, version)) + continue; + if (auto *added = + dyn_cast(versionedAttr->getAttrToAdd())) { + return added; + } + } + + if (auto *removeAttr = dyn_cast(attr)) { + if (!matchesVersion(removeAttr, version)) + continue; + if (removeAttr->getAttrKindToRemove() == clang::attr::SwiftName) + return nullptr; + } + } + + return decl->getAttr(); + } + + // The remainder of this function emulates the limited form of swift_name + // supported in Swift 2. + auto attr = decl->getAttr(); + if (!attr) return nullptr; + + // API notes produce implicit attributes; ignore them because they weren't + // used for naming in Swift 2. + if (attr->isImplicit()) return nullptr; + + // Whitelist certain explicitly-written Swift names that were + // permitted and used in Swift 2. All others are ignored, so that we are + // assuming a more direct translation from the Objective-C APIs into Swift. + + if (auto enumerator = dyn_cast(decl)) { + // Foundation's NSXMLDTDKind had an explicit swift_name attribute in + // Swift 2. Honor it. + if (enumerator->getName() == "NSXMLDTDKind") return attr; + return nullptr; + } + + if (auto method = dyn_cast(decl)) { + // Special case: mapping to an initializer. + if (attr->getName().startswith("init(")) { + // If we have a class method, honor the annotation to turn a class + // method into an initializer. + if (method->isClassMethod()) return attr; + + return nullptr; + } + + // Special case: preventing a mapping to an initializer. + if (matchFactoryAsInitName(method) && determineCtorInitializerKind(method)) + return attr; + + return nullptr; + } + + return nullptr; +} + /// Determine whether the given class method should be imported as /// an initializer. static FactoryAsInitKind getFactoryAsInit(const clang::ObjCInterfaceDecl *classDecl, - const clang::ObjCMethodDecl *method) { - if (auto *customNameAttr = method->getAttr()) { + const clang::ObjCMethodDecl *method, + ImportNameVersion version) { + if (auto *customNameAttr = findSwiftNameAttr(method, version)) { if (customNameAttr->getName().startswith("init(")) return FactoryAsInitKind::AsInitializer; else @@ -586,6 +678,7 @@ getFactoryAsInit(const clang::ObjCInterfaceDecl *classDecl, /// imported. Note that this does not distinguish designated /// vs. convenience; both will be classified as "designated". static bool shouldImportAsInitializer(const clang::ObjCMethodDecl *method, + ImportNameVersion version, unsigned &prefixLength, CtorInitializerKind &kind) { /// Is this an initializer? @@ -604,7 +697,7 @@ static bool shouldImportAsInitializer(const clang::ObjCMethodDecl *method, // Check whether we should try to import this factory method as an // initializer. - switch (getFactoryAsInit(objcClass, method)) { + switch (getFactoryAsInit(objcClass, method, version)) { case FactoryAsInitKind::AsInitializer: // Okay; check for the correct result type below. prefixLength = 0; @@ -634,55 +727,6 @@ static bool shouldImportAsInitializer(const clang::ObjCMethodDecl *method, return false; } -/// Find the swift_name attribute associated with this declaration, if -/// any. -/// -/// \param version The version we're importing the name as -static clang::SwiftNameAttr *findSwiftNameAttr(const clang::Decl *decl, - ImportNameVersion version) { - // Find the attribute. - auto attr = decl->getAttr(); - if (!attr) return nullptr; - - // If we're not emulating the Swift 2 behavior, return what we got. - if (version != ImportNameVersion::Swift2) - return attr; - - // API notes produce implicit attributes; ignore them because they weren't - // used for naming in Swift 2. - if (attr->isImplicit()) return nullptr; - - // Whitelist certain explicitly-written Swift names that were - // permitted and used in Swift 2. All others are ignored, so that we are - // assuming a more direct translation from the Objective-C APIs into Swift. - - if (auto enumerator = dyn_cast(decl)) { - // Foundation's NSXMLDTDKind had an explicit swift_name attribute in - // Swift 2. Honor it. - if (enumerator->getName() == "NSXMLDTDKind") return attr; - return nullptr; - } - - if (auto method = dyn_cast(decl)) { - // Special case: mapping to an initializer. - if (attr->getName().startswith("init(")) { - // If we have a class method, honor the annotation to turn a class - // method into an initializer. - if (method->isClassMethod()) return attr; - - return nullptr; - } - - // Special case: preventing a mapping to an initializer. - if (matchFactoryAsInitName(method) && determineCtorInitializerKind(method)) - return attr; - - return nullptr; - } - - return nullptr; -} - /// Attempt to omit needless words from the given function name. static bool omitNeedlessWordsInFunctionName( StringRef &baseName, SmallVectorImpl &argumentNames, @@ -1179,7 +1223,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (method) { unsigned initPrefixLength; if (parsedName.BaseName == "init" && parsedName.IsFunctionName) { - if (!shouldImportAsInitializer(method, initPrefixLength, + if (!shouldImportAsInitializer(method, version, initPrefixLength, result.info.initKind)) { // We cannot import this as an initializer anyway. return ImportedName(); @@ -1354,7 +1398,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (baseName.empty()) return ImportedName(); - isInitializer = shouldImportAsInitializer(objcMethod, initializerPrefixLen, + isInitializer = shouldImportAsInitializer(objcMethod, version, + initializerPrefixLen, result.info.initKind); // If we would import a factory method as an initializer but were diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index 9bedf0272be07..fa622eeaa6f9c 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -25,9 +25,6 @@ #include "swift/AST/ForeignErrorConvention.h" #include "clang/Sema/Sema.h" -// TODO: remove when we drop import name options -#include "clang/AST/Decl.h" - namespace swift { namespace importer { struct PlatformAvailability; @@ -55,12 +52,36 @@ enum class ImportNameVersion : unsigned { /// Names as they appeared in Swift 4 family Swift4, + + /// A placeholder for the latest version, to be used in loops and such. + LAST_VERSION = Swift4 }; -enum { NumImportNameVersions = 4 }; -/// Map a language version into an import name version +static inline void +forEachImportNameVersion(llvm::function_ref action) { + auto limit = static_cast(ImportNameVersion::LAST_VERSION); + for (unsigned raw = 0; raw <= limit; ++raw) + action(static_cast(raw)); +} + +static inline ImportNameVersion &operator++(ImportNameVersion &value) { + assert(value != ImportNameVersion::LAST_VERSION); + value = static_cast(static_cast(value) + 1); + return value; +} + +static inline ImportNameVersion &operator--(ImportNameVersion &value) { + assert(value != ImportNameVersion::Raw); + value = static_cast(static_cast(value) - 1); + return value; +} + +/// Map a language version into an import name version. ImportNameVersion nameVersionFromOptions(const LangOptions &langOpts); +/// Map an import name version into a language version. +unsigned majorVersionNumberForNameVersion(ImportNameVersion version); + /// Describes a name that was imported from Clang. class ImportedName { friend class NameImporter; @@ -221,6 +242,11 @@ class ImportedName { /// in "Notification", or it there would be nothing left. StringRef stripNotification(StringRef name); +/// Find the swift_name attribute associated with this declaration, if any, +/// appropriate for \p version. +const clang::SwiftNameAttr *findSwiftNameAttr(const clang::Decl *decl, + ImportNameVersion version); + /// Class to determine the Swift name of foreign entities. Currently fairly /// stateless and borrows from the ClangImporter::Implementation, but in the /// future will be more self-contained and encapsulated. diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 841c171a98bb7..36e4dfa5d9196 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1626,7 +1626,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( } // Figure out the name for this parameter. - Identifier bodyName = importFullName(param, ImportNameVersion::Swift3) + Identifier bodyName = importFullName(param, CurrentVersion) .getDeclName() .getBaseName(); @@ -2037,7 +2037,7 @@ Type ClangImporter::Implementation::importMethodType( } // Figure out the name for this parameter. - Identifier bodyName = importFullName(param, ImportNameVersion::Swift3) + Identifier bodyName = importFullName(param, CurrentVersion) .getDeclName() .getBaseName(); @@ -2194,7 +2194,7 @@ Type ClangImporter::Implementation::importAccessorMethodType( } else { const clang::ParmVarDecl *param = clangDecl->parameters().front(); - ImportedName fullBodyName = importFullName(param,ImportNameVersion::Swift3); + ImportedName fullBodyName = importFullName(param, CurrentVersion); Identifier bodyName = fullBodyName.getDeclName().getBaseName(); SourceLoc nameLoc = importSourceLoc(param->getLocation()); Identifier argLabel = functionName.getDeclName().getArgumentNames().front(); diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index c16878c25e245..5b4f30fd6ca58 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1541,8 +1541,11 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, } // If we have a name to import as, add this entry to the table. - if (auto importedName = - nameImporter.importName(named, ImportNameVersion::Swift3)) { + ImportNameVersion currentVersion = + nameVersionFromOptions(nameImporter.getLangOpts()); + if (auto importedName = nameImporter.importName(named, currentVersion)) { + SmallPtrSet distinctNames; + distinctNames.insert(importedName.getDeclName()); table.addEntry(importedName.getDeclName(), named, importedName.getEffectiveContext()); @@ -1553,14 +1556,19 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, ArrayRef()), named, importedName.getEffectiveContext()); - // Import the Swift 2 name of this entity, and record it as well if it is - // different. - if (auto swift2Name = - nameImporter.importName(named, ImportNameVersion::Swift2)) { - if (swift2Name.getDeclName() != importedName.getDeclName()) - table.addEntry(swift2Name.getDeclName(), named, - swift2Name.getEffectiveContext()); - } + forEachImportNameVersion([&] (ImportNameVersion alternateVersion) { + if (alternateVersion == currentVersion) + return; + auto alternateName = nameImporter.importName(named, alternateVersion); + if (!alternateName) + return; + // FIXME: What if the DeclNames are the same but the contexts are + // different? + if (distinctNames.insert(alternateName.getDeclName()).second) { + table.addEntry(alternateName.getDeclName(), named, + alternateName.getEffectiveContext()); + } + }); } else if (auto category = dyn_cast(named)) { // If the category is invalid, don't add it. if (category->isInvalidDecl()) diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes index 747e0bb9ed663..3cff8ce99f7bd 100644 --- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes +++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes @@ -79,7 +79,16 @@ SwiftVersions: - Name: accessorsOnlyRenamedRetypedClass PropertyKind: Class SwiftImportAsAccessors: true + Protocols: + - Name: ProtoWithVersionedUnavailableMember + Methods: + - Selector: requirement + MethodKind: Instance + ResultType: 'ForwardClass * _Nullable' Functions: - Name: acceptDoublePointer SwiftName: 'acceptPointer(_:)' Nullability: [ O ] + Tags: + - Name: SomeCStruct + SwiftName: ImportantCStruct diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h index b0a6023e0c4b9..92858ee3a8735 100644 --- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h +++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h @@ -2,6 +2,11 @@ void jumpToLocation(double x, double y, double z); void acceptDoublePointer(double* _Nonnull ptr) __attribute__((swift_name("accept(_:)"))); +void oldAcceptDoublePointer(double* _Nonnull ptr) __attribute__((availability(swift, unavailable, replacement="acceptDoublePointer"))); + + +#import + #ifdef __OBJC__ __attribute__((objc_root_class)) @@ -14,4 +19,6 @@ __attribute__((objc_root_class)) @end #import -#endif +#import + +#endif // __OBJC__ diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h new file mode 100644 index 0000000000000..f68392d942280 --- /dev/null +++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Protocols.h @@ -0,0 +1,9 @@ +#pragma clang assume_nonnull begin + +@class ForwardClass; // used by API notes + +@protocol ProtoWithVersionedUnavailableMember +- (nullable id)requirement; +@end + +#pragma clang assume_nonnull end diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h new file mode 100644 index 0000000000000..c44439fd74fd3 --- /dev/null +++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Types.h @@ -0,0 +1,7 @@ +#pragma clang assume_nonnull begin + +struct __attribute__((swift_name("VeryImportantCStruct"))) SomeCStruct { + int field; +}; + +#pragma clang assume_nonnull end diff --git a/test/APINotes/versioned.swift b/test/APINotes/versioned.swift index 98d8b85e67b31..c5f1712a2d1e6 100644 --- a/test/APINotes/versioned.swift +++ b/test/APINotes/versioned.swift @@ -9,3 +9,56 @@ // CHECK-SWIFT-4: func accept(_ ptr: UnsafeMutablePointer) // CHECK-SWIFT-3: func acceptPointer(_ ptr: UnsafeMutablePointer?) + +// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s +// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 3 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-3 %s + +import APINotesFrameworkTest + +// CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE-1]]: +class ProtoWithVersionedUnavailableMemberImpl: ProtoWithVersionedUnavailableMember { + // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:7: error: type 'ProtoWithVersionedUnavailableMemberImpl' cannot conform to protocol 'ProtoWithVersionedUnavailableMember' because it has requirements that cannot be satisfied + func requirement() -> Any? { return nil } +} + +func testRenamedTopLevel() { + var value = 0.0 + + // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]: + accept(&value) + // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:3: error: 'accept' has been renamed to 'acceptPointer(_:)' + // CHECK-DIAGS-3: note: 'accept' was introduced in Swift 4 + + // CHECK-DIAGS-3-NOT: versioned.swift:[[@LINE+1]]: + acceptPointer(&value) + // CHECK-DIAGS-4: versioned.swift:[[@LINE-1]]:3: error: 'acceptPointer' has been renamed to 'accept(_:)' + // CHECK-DIAGS-4: note: 'acceptPointer' was obsoleted in Swift 4 + + acceptDoublePointer(&value) + // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:3: error: 'acceptDoublePointer' has been renamed to + // CHECK-DIAGS-4-SAME: 'accept(_:)' + // CHECK-DIAGS-3-SAME: 'acceptPointer(_:)' + // CHECK-DIAGS: note: 'acceptDoublePointer' was obsoleted in Swift 3 + + oldAcceptDoublePointer(&value) + // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:3: error: 'oldAcceptDoublePointer' has been renamed to + // CHECK-DIAGS-4-SAME: 'accept(_:)' + // CHECK-DIAGS-3-SAME: 'acceptPointer(_:)' + // CHECK-DIAGS: note: 'oldAcceptDoublePointer' has been explicitly marked unavailable here + + _ = SomeCStruct() + // CHECK-DIAGS: versioned.swift:[[@LINE-1]]:7: error: 'SomeCStruct' has been renamed to + // CHECK-DIAGS-4-SAME: 'VeryImportantCStruct' + // CHECK-DIAGS-3-SAME: 'ImportantCStruct' + // CHECK-DIAGS: note: 'SomeCStruct' was obsoleted in Swift 3 + + // CHECK-DIAGS-3-NOT: versioned.swift:[[@LINE+1]]: + _ = ImportantCStruct() + // CHECK-DIAGS-4: versioned.swift:[[@LINE-1]]:7: error: 'ImportantCStruct' has been renamed to 'VeryImportantCStruct' + // CHECK-DIAGS-4: note: 'ImportantCStruct' was obsoleted in Swift 4 + + // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]: + _ = VeryImportantCStruct() + // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:7: error: 'VeryImportantCStruct' has been renamed to 'ImportantCStruct' + // CHECK-DIAGS-3: note: 'VeryImportantCStruct' was introduced in Swift 4 +} diff --git a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt index b1e788e0f5d85..ae6f5db0d9354 100644 --- a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt +++ b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt @@ -9,8 +9,14 @@ class Foo : NSObject, __PrivProto { func __oneArg(_ arg: Int32) func __twoArgs(_ arg: Int32, other arg2: Int32) class func __withNoArgs() -> Self! + @available(*, unavailable, renamed: "init(__oneArg:)", message: "Not available in Swift") + class func __fooWithOneArg(_ arg: Int32) -> Self! convenience init!(__oneArg arg: Int32) + @available(*, unavailable, renamed: "init(__twoArgs:other:)", message: "Not available in Swift") + class func __fooWithTwoArgs(_ arg: Int32, other arg2: Int32) -> Self! convenience init!(__twoArgs arg: Int32, other arg2: Int32) + @available(*, unavailable, renamed: "init(__:)", message: "Not available in Swift") + class func __foo(_ arg: Int32) -> Self! convenience init!(__ arg: Int32) func objectForKeyedSubscript(_ index: Any!) -> Any! func __setObject(_ object: Any!, forKeyedSubscript index: Any!) diff --git a/test/ClangImporter/attr-swift_private.swift b/test/ClangImporter/attr-swift_private.swift index 0bd1079d588a2..b914821b189b1 100644 --- a/test/ClangImporter/attr-swift_private.swift +++ b/test/ClangImporter/attr-swift_private.swift @@ -135,8 +135,8 @@ _ = 1 as __PrivInt #if !IRGEN func testRawNames() { - let _ = Foo.__fooWithOneArg(0) // expected-error {{'__fooWithOneArg' is unavailable: use object construction 'Foo(__oneArg:)'}} - let _ = Foo.__foo // expected-error{{'__foo' is unavailable: use object construction 'Foo(__:)'}} + let _ = Foo.__fooWithOneArg(0) // expected-error {{'__fooWithOneArg' has been replaced by 'init(__oneArg:)'}} + let _ = Foo.__foo // expected-error{{'__foo' has been replaced by 'init(__:)'}} } #endif diff --git a/test/ClangImporter/objc_factory_method.swift b/test/ClangImporter/objc_factory_method.swift index 9b7a64da3ef9a..b26ff08212548 100644 --- a/test/ClangImporter/objc_factory_method.swift +++ b/test/ClangImporter/objc_factory_method.swift @@ -84,7 +84,7 @@ func testNonInstanceTypeFactoryMethod(_ s: String) { } func testUseOfFactoryMethod(_ queen: Bee) { - _ = Hive.hiveWithQueen(queen) // expected-error{{'hiveWithQueen' is unavailable: use object construction 'Hive(queen:)'}} + _ = Hive.hiveWithQueen(queen) // expected-error{{'hiveWithQueen' has been replaced by 'init(queen:)'}} {{11-25=}} {{26-26=queen: }} } func testNonsplittableFactoryMethod() { @@ -97,18 +97,18 @@ func testFactoryMethodBlacklist() { func test17261609() { _ = NSDecimalNumber(mantissa:1, exponent:1, isNegative:true) - _ = NSDecimalNumber.decimalNumberWithMantissa(1, exponent:1, isNegative:true) // expected-error{{'decimalNumberWithMantissa(_:exponent:isNegative:)' is unavailable: use object construction 'NSDecimalNumber(mantissa:exponent:isNegative:)'}} + _ = NSDecimalNumber.decimalNumberWithMantissa(1, exponent:1, isNegative:true) // expected-error{{'decimalNumberWithMantissa(_:exponent:isNegative:)' has been replaced by 'init(mantissa:exponent:isNegative:)'}} {{22-48=}} {{49-49=mantissa: }} } func testURL() { let url = NSURL(string: "http://www.llvm.org")! - _ = NSURL.URLWithString("http://www.llvm.org") // expected-error{{'URLWithString' is unavailable: use object construction 'NSURL(string:)'}} + _ = NSURL.URLWithString("http://www.llvm.org") // expected-error{{'URLWithString' has been replaced by 'init(string:)'}} {{12-26=}} {{27-27=string: }} NSURLRequest(string: "http://www.llvm.org") // expected-warning{{unused}} NSURLRequest(url: url as URL) // expected-warning{{unused}} - _ = NSURLRequest.requestWithString("http://www.llvm.org") // expected-error{{'requestWithString' is unavailable: use object construction 'NSURLRequest(string:)'}} - _ = NSURLRequest.URLRequestWithURL(url as URL) // expected-error{{'URLRequestWithURL' is unavailable: use object construction 'NSURLRequest(url:)'}} + _ = NSURLRequest.requestWithString("http://www.llvm.org") // expected-error{{'requestWithString' has been replaced by 'init(string:)'}} + _ = NSURLRequest.URLRequestWithURL(url as URL) // expected-error{{'URLRequestWithURL' has been replaced by 'init(url:)'}} } // FIXME: Remove -verify-ignore-unknown. diff --git a/test/ClangImporter/objc_implicit_with.swift b/test/ClangImporter/objc_implicit_with.swift index 7d266897f83f5..1aeebb4a89752 100644 --- a/test/ClangImporter/objc_implicit_with.swift +++ b/test/ClangImporter/objc_implicit_with.swift @@ -50,7 +50,7 @@ func testNonInstanceTypeFactoryMethod(_ s: String) { } func testUseOfFactoryMethod(_ queen: Bee) { - _ = Hive.hiveWithQueen(queen) // expected-error{{'hiveWithQueen' is unavailable: use object construction 'Hive(queen:)'}} + _ = Hive.hiveWithQueen(queen) // expected-error{{'hiveWithQueen' has been replaced by 'init(queen:)'}} {{11-25=}} {{26-26=queen: }} } func testNonsplittableFactoryMethod() { diff --git a/test/IDE/Inputs/swift_name_objc.h b/test/IDE/Inputs/swift_name_objc.h index aaf133a396244..33c6476d5e38b 100644 --- a/test/IDE/Inputs/swift_name_objc.h +++ b/test/IDE/Inputs/swift_name_objc.h @@ -61,9 +61,6 @@ SWIFT_NAME(SomeProtocol) -(instancetype)initWithTitle:(const char *)title delegate:(id)delegate cancelButtonTitle:(const char *)cancelButtonTitle destructiveButtonTitle:(const char *)destructiveButtonTitle otherButtonTitles:(const char *)otherButtonTitles, ...; @end -@interface NSError : NSObject -@end - @interface NSErrorImports : NSObject - (nullable NSObject *)methodAndReturnError:(NSError **)error; - (BOOL)methodWithFloat:(float)value error:(NSError **)error; diff --git a/test/IDE/dump_swift_lookup_tables_objc.swift b/test/IDE/dump_swift_lookup_tables_objc.swift index 0428976a32264..cff7a367cffa9 100644 --- a/test/IDE/dump_swift_lookup_tables_objc.swift +++ b/test/IDE/dump_swift_lookup_tables_objc.swift @@ -29,14 +29,16 @@ // CHECK-NEXT: TU: CFTypeRef // CHECK-NEXT: NSAccessibility: // CHECK-NEXT: TU: NSAccessibility{{$}} -// CHECK-NEXT: NSError: -// CHECK-NEXT: TU: NSError // CHECK-NEXT: NSErrorImports: // CHECK-NEXT: TU: NSErrorImports // CHECK-NEXT: SNCollision: // CHECK-NEXT: TU: SNCollision{{$}} // CHECK-NEXT: SNCollisionProtocol: // CHECK-NEXT: TU: SNCollision{{$}} +// CHECK-NEXT: SNSomeClass: +// CHECK-NEXT: TU: SNSomeClass +// CHECK-NEXT: SNSomeProtocol: +// CHECK-NEXT: TU: SNSomeProtocol // CHECK-NEXT: SomeClass: // CHECK-NEXT: TU: SNSomeClass // CHECK-NEXT: SomeProtocol: @@ -51,12 +53,18 @@ // CHECK-NEXT: NSErrorImports: -[NSErrorImports badPointerMethodAndReturnError:] // CHECK-NEXT: blockMethod: // CHECK-NEXT: NSErrorImports: -[NSErrorImports blockMethodAndReturnError:] +// CHECK-NEXT: buildWithUnsignedChar: +// CHECK-NEXT: SNSomeClass: +[SNSomeClass buildWithUnsignedChar:] // CHECK-NEXT: categoryMethodWith: // CHECK-NEXT: SNSomeClass: -[SNSomeClass categoryMethodWithX:y:], -[SNSomeClass categoryMethodWithX:y:z:] +// CHECK-NEXT: categoryMethodWithX: +// CHECK-NEXT: SNSomeClass: -[SNSomeClass categoryMethodWithX:y:], -[SNSomeClass categoryMethodWithX:y:z:] // CHECK: doubleProperty: // CHECK-NEXT: SNSomeClass: SNSomeClass.doubleProperty // CHECK-NEXT: extensionMethodWith: // CHECK-NEXT: SNSomeClass: -[SNSomeClass extensionMethodWithX:y:] +// CHECK-NEXT: extensionMethodWithX: +// CHECK-NEXT: SNSomeClass: -[SNSomeClass extensionMethodWithX:y:] // CHECK: floatProperty: // CHECK-NEXT: SNSomeClass: SNSomeClass.floatProperty // CHECK-NEXT: functionPointerMethod: @@ -67,8 +75,12 @@ // CHECK-NEXT: NSErrorImports: -[NSErrorImports initAndReturnError:], -[NSErrorImports initWithFloat:error:] // CHECK-NEXT: instanceMethodWith: // CHECK-NEXT: SNSomeClass: -[SNSomeClass instanceMethodWithX:Y:Z:] +// CHECK-NEXT: instanceMethodWithX: +// CHECK-NEXT: SNSomeClass: -[SNSomeClass instanceMethodWithX:Y:Z:] // CHECK: method: // CHECK-NEXT: NSErrorImports: -[NSErrorImports methodAndReturnError:], -[NSErrorImports methodWithFloat:error:] +// CHECK: methodWithFloat: +// CHECK-NEXT: NSErrorImports: -[NSErrorImports methodWithFloat:error:] // CHECK: objectAtIndexedSubscript: // CHECK-NEXT: SNSomeClass: -[SNSomeClass objectAtIndexedSubscript:] // CHECK-NEXT: optSetter: @@ -77,12 +89,18 @@ // CHECK-NEXT: NSErrorImports: -[NSErrorImports pointerMethodAndReturnError:] // CHECK-NEXT: protoInstanceMethodWith: // CHECK-NEXT: SNSomeProtocol: -[SNSomeProtocol protoInstanceMethodWithX:y:] +// CHECK-NEXT: protoInstanceMethodWithX: +// CHECK-NEXT: SNSomeProtocol: -[SNSomeProtocol protoInstanceMethodWithX:y:] // CHECK: reqSetter: // CHECK-NEXT: SNCollision: SNCollision.reqSetter // CHECK-NEXT: selectorMethod: // CHECK-NEXT: NSErrorImports: -[NSErrorImports selectorMethodAndReturnError:] // CHECK-NEXT: setAccessibilityFloat: // CHECK-NEXT: NSAccessibility: -[NSAccessibility setAccessibilityFloat:] +// CHECK-NEXT: someClassWithDouble: +// CHECK-NEXT: SNSomeClass: +[SNSomeClass someClassWithDouble:] +// CHECK-NEXT: someClassWithTry: +// CHECK-NEXT: SNSomeClass: +[SNSomeClass someClassWithTry:] // CHECK-NEXT: subscript: // CHECK-NEXT: SNSomeClass: -[SNSomeClass objectAtIndexedSubscript:] diff --git a/test/IDE/print_clang_swift_name.swift b/test/IDE/print_clang_swift_name.swift index 8f798b2dd0523..9048e5db4c907 100644 --- a/test/IDE/print_clang_swift_name.swift +++ b/test/IDE/print_clang_swift_name.swift @@ -11,15 +11,28 @@ class Test : NSObject { + // "Factory methods" that we'd rather have as initializers. + @available(*, unavailable, renamed: "init()", message: "Not available in Swift") + class func a() -> Self @available(*, unavailable, message: "superseded by import of -[NSObject init]") convenience init() + @available(*, unavailable, renamed: "init(dummyParam:)", message: "Not available in Swift") + class func b() -> Self convenience init(dummyParam: ()) + @available(*, unavailable, renamed: "init(cc:)", message: "Not available in Swift") + class func c(_ x: Any) -> Self convenience init(cc x: Any) + @available(*, unavailable, renamed: "init(_:)", message: "Not available in Swift") + class func d(_ x: Any) -> Self convenience init(_ x: Any) + @available(*, unavailable, renamed: "init(aa:_:cc:)", message: "Not available in Swift") + class func e(_ a: Any, e b: Any, e c: Any) -> Self convenience init(aa a: Any, _ b: Any, cc c: Any) + @available(*, unavailable, renamed: "init(fixedType:)", message: "Not available in Swift") + class func f() -> Test /*not inherited*/ init(fixedType: ()) // Would-be initializers. @@ -31,14 +44,28 @@ class Test : NSObject { } class TestError : NSObject { - + // Factory methods with NSError. + @available(*, unavailable, renamed: "init(error:)", message: "Not available in Swift") + class func err1() throws -> Self convenience init(error: ()) throws + @available(*, unavailable, renamed: "init(aa:error:)", message: "Not available in Swift") + class func err2(_ x: Any?) throws -> Self convenience init(aa x: Any?, error: ()) throws + @available(*, unavailable, renamed: "init(aa:error:block:)", message: "Not available in Swift") + class func err3(_ x: Any?, callback block: @escaping () -> Void) throws -> Self convenience init(aa x: Any?, error: (), block: @escaping () -> Void) throws + @available(*, unavailable, renamed: "init(error:block:)", message: "Not available in Swift") + class func err4(callback block: @escaping () -> Void) throws -> Self convenience init(error: (), block: @escaping () -> Void) throws + @available(*, unavailable, renamed: "init(aa:)", message: "Not available in Swift") + class func err5(_ x: Any?) throws -> Self convenience init(aa x: Any?) throws + @available(*, unavailable, renamed: "init(aa:block:)", message: "Not available in Swift") + class func err6(_ x: Any?, callback block: @escaping () -> Void) throws -> Self convenience init(aa x: Any?, block: @escaping () -> Void) throws + @available(*, unavailable, renamed: "init(block:)", message: "Not available in Swift") + class func err7(callback block: @escaping () -> Void) throws -> Self convenience init(block: @escaping () -> Void) throws // Would-be initializers.