| //===--- ClangAdapter.cpp - Interfaces with Clang entities ----------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file provides convenient and canonical interfaces with Clang entities, |
| // serving as both a useful place to put utility functions and a canonical |
| // interface that can abstract nitty gritty Clang internal details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CFTypeInfo.h" |
| #include "ClangAdapter.h" |
| #include "ImportName.h" |
| #include "ImporterImpl.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/Lex/Lexer.h" |
| #include "clang/Sema/Lookup.h" |
| #include "clang/Sema/Sema.h" |
| |
| using namespace swift; |
| using namespace importer; |
| |
| /// Get a bit vector indicating which arguments are non-null for a |
| /// given function or method. |
| llvm::SmallBitVector |
| importer::getNonNullArgs(const clang::Decl *decl, |
| ArrayRef<const clang::ParmVarDecl *> params) { |
| llvm::SmallBitVector result; |
| if (!decl) |
| return result; |
| |
| for (const auto *nonnull : decl->specific_attrs<clang::NonNullAttr>()) { |
| if (!nonnull->args_size()) { |
| // Easy case: all pointer arguments are non-null. |
| if (result.empty()) |
| result.resize(params.size(), true); |
| else |
| result.set(0, params.size()); |
| |
| return result; |
| } |
| |
| // Mark each of the listed parameters as non-null. |
| if (result.empty()) |
| result.resize(params.size(), false); |
| |
| for (unsigned idx : nonnull->args()) { |
| if (idx < result.size()) |
| result.set(idx); |
| } |
| } |
| |
| return result; |
| } |
| |
| Optional<const clang::Decl *> |
| importer::getDefinitionForClangTypeDecl(const clang::Decl *D) { |
| if (auto OID = dyn_cast<clang::ObjCInterfaceDecl>(D)) |
| return OID->getDefinition(); |
| |
| if (auto TD = dyn_cast<clang::TagDecl>(D)) |
| return TD->getDefinition(); |
| |
| if (auto OPD = dyn_cast<clang::ObjCProtocolDecl>(D)) |
| return OPD->getDefinition(); |
| |
| return None; |
| } |
| |
| Optional<clang::Module *> |
| importer::getClangSubmoduleForDecl(const clang::Decl *D, |
| bool allowForwardDeclaration) { |
| const clang::Decl *actual = nullptr; |
| |
| // Put an Objective-C class into the module that contains the @interface |
| // definition, not just some @class forward declaration. |
| if (auto maybeDefinition = getDefinitionForClangTypeDecl(D)) { |
| actual = maybeDefinition.getValue(); |
| if (!actual && !allowForwardDeclaration) |
| return None; |
| } |
| |
| if (!actual) |
| actual = D->getCanonicalDecl(); |
| |
| return actual->getImportedOwningModule(); |
| } |
| |
| /// Retrieve the instance type of the given Clang declaration context. |
| clang::QualType |
| importer::getClangDeclContextType(const clang::DeclContext *dc) { |
| auto &ctx = dc->getParentASTContext(); |
| if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(dc)) |
| return ctx.getObjCObjectPointerType(ctx.getObjCInterfaceType(objcClass)); |
| |
| if (auto objcCategory = dyn_cast<clang::ObjCCategoryDecl>(dc)) { |
| if (objcCategory->isInvalidDecl()) |
| return clang::QualType(); |
| |
| return ctx.getObjCObjectPointerType( |
| ctx.getObjCInterfaceType(objcCategory->getClassInterface())); |
| } |
| |
| if (auto constProto = dyn_cast<clang::ObjCProtocolDecl>(dc)) { |
| auto proto = const_cast<clang::ObjCProtocolDecl *>(constProto); |
| auto type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, {}, {proto}, false); |
| return ctx.getObjCObjectPointerType(type); |
| } |
| |
| if (auto tag = dyn_cast<clang::TagDecl>(dc)) { |
| return ctx.getTagDeclType(tag); |
| } |
| |
| return clang::QualType(); |
| } |
| |
| /// Determine whether this is the name of a collection with a single |
| /// element type. |
| static bool isCollectionName(StringRef typeName) { |
| auto lastWord = camel_case::getLastWord(typeName); |
| return lastWord == "Array" || lastWord == "Set"; |
| } |
| |
| /// Retrieve the name of the given Clang type for use when omitting |
| /// needless words. |
| OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, |
| clang::QualType type) { |
| if (type.isNull()) |
| return OmissionTypeName(); |
| |
| // Dig through the type, looking for a typedef-name and stripping |
| // references along the way. |
| StringRef lastTypedefName; |
| do { |
| // The name of a typedef-name. |
| auto typePtr = type.getTypePtr(); |
| if (auto typedefType = dyn_cast<clang::TypedefType>(typePtr)) { |
| auto name = typedefType->getDecl()->getName(); |
| |
| // Objective-C selector type. |
| if (ctx.hasSameUnqualifiedType(type, ctx.getObjCSelType()) && |
| name == "SEL") |
| return "Selector"; |
| |
| // Objective-C "id" type. |
| if (type->isObjCIdType() && name == "id") |
| return "Object"; |
| |
| // Objective-C "Class" type. |
| if (type->isObjCClassType() && name == "Class") |
| return "Class"; |
| |
| // Objective-C "BOOL" type. |
| if (name == "BOOL") |
| return OmissionTypeName("Bool", OmissionTypeFlags::Boolean); |
| |
| // If this is an imported CF type, use that name. |
| StringRef CFName = getCFTypeName(typedefType->getDecl()); |
| if (!CFName.empty()) |
| return CFName; |
| |
| // If we have NS(U)Integer or CGFloat, return it. |
| if (name == "NSInteger" || name == "NSUInteger" || name == "CGFloat") |
| return name; |
| |
| // If it's a collection name and of pointer type, call it an |
| // array of the pointee type. |
| if (isCollectionName(name)) { |
| if (auto ptrType = type->getAs<clang::PointerType>()) { |
| return OmissionTypeName( |
| name, None, |
| getClangTypeNameForOmission(ctx, ptrType->getPointeeType()).Name); |
| } |
| } |
| |
| // Otherwise, desugar one level... |
| lastTypedefName = name; |
| type = typedefType->getDecl()->getUnderlyingType(); |
| continue; |
| } |
| |
| // For array types, convert the element type and treat this an as array. |
| if (auto arrayType = dyn_cast<clang::ArrayType>(typePtr)) { |
| return OmissionTypeName( |
| "Array", None, |
| getClangTypeNameForOmission(ctx, arrayType->getElementType()).Name); |
| } |
| |
| // Look through reference types. |
| if (auto refType = dyn_cast<clang::ReferenceType>(typePtr)) { |
| type = refType->getPointeeTypeAsWritten(); |
| continue; |
| } |
| |
| // Look through pointer types. |
| if (auto ptrType = dyn_cast<clang::PointerType>(typePtr)) { |
| type = ptrType->getPointeeType(); |
| continue; |
| } |
| |
| // Try to desugar one level... |
| clang::QualType desugared = type.getSingleStepDesugaredType(ctx); |
| if (desugared.getTypePtr() == type.getTypePtr()) |
| break; |
| |
| type = desugared; |
| } while (true); |
| |
| // Objective-C object pointers. |
| if (auto objcObjectPtr = type->getAs<clang::ObjCObjectPointerType>()) { |
| auto objcClass = objcObjectPtr->getInterfaceDecl(); |
| |
| // For id<Proto> or NSObject<Proto>, retrieve the name of "Proto". |
| if (objcObjectPtr->getNumProtocols() == 1 && |
| (!objcClass || objcClass->getName() == "NSObject")) |
| return (*objcObjectPtr->qual_begin())->getName(); |
| |
| // If there is a class, use it. |
| if (objcClass) { |
| // If this isn't the name of an Objective-C collection, we're done. |
| auto className = objcClass->getName(); |
| if (!isCollectionName(className)) |
| return className; |
| |
| // If we don't have type parameters, use the prefix of the type |
| // name as the collection element type. |
| if (objcClass && !objcClass->getTypeParamList()) { |
| unsigned lastWordSize = camel_case::getLastWord(className).size(); |
| StringRef elementName = |
| className.substr(0, className.size() - lastWordSize); |
| return OmissionTypeName(className, None, elementName); |
| } |
| |
| // If we don't have type arguments, the collection element type |
| // is "Object". |
| auto typeArgs = objcObjectPtr->getTypeArgs(); |
| if (typeArgs.empty()) |
| return OmissionTypeName(className, None, "Object"); |
| |
| return OmissionTypeName( |
| className, None, getClangTypeNameForOmission(ctx, typeArgs[0]).Name); |
| } |
| |
| // Objective-C "id" type. |
| if (objcObjectPtr->isObjCIdType()) |
| return "Object"; |
| |
| // Objective-C "Class" type. |
| if (objcObjectPtr->isObjCClassType()) |
| return "Class"; |
| |
| return StringRef(); |
| } |
| |
| // Handle builtin types by importing them and getting the Swift name. |
| if (auto builtinTy = type->getAs<clang::BuiltinType>()) { |
| // Names of integer types. |
| static const char *intTypeNames[] = {"UInt8", "UInt16", "UInt32", "UInt64", |
| "UInt128"}; |
| |
| /// Retrieve the name for an integer type based on its size. |
| auto getIntTypeName = [&](bool isSigned) -> StringRef { |
| switch (ctx.getTypeSize(builtinTy)) { |
| case 8: |
| return StringRef(intTypeNames[0]).substr(isSigned ? 1 : 0); |
| case 16: |
| return StringRef(intTypeNames[1]).substr(isSigned ? 1 : 0); |
| case 32: |
| return StringRef(intTypeNames[2]).substr(isSigned ? 1 : 0); |
| case 64: |
| return StringRef(intTypeNames[3]).substr(isSigned ? 1 : 0); |
| case 128: |
| return StringRef(intTypeNames[4]).substr(isSigned ? 1 : 0); |
| default: |
| llvm_unreachable("bad integer type size"); |
| } |
| }; |
| |
| switch (builtinTy->getKind()) { |
| case clang::BuiltinType::Void: |
| return "Void"; |
| |
| case clang::BuiltinType::Bool: |
| return OmissionTypeName("Bool", OmissionTypeFlags::Boolean); |
| |
| case clang::BuiltinType::Float: |
| return "Float"; |
| |
| case clang::BuiltinType::Double: |
| return "Double"; |
| |
| case clang::BuiltinType::Char16: |
| return "UInt16"; |
| |
| case clang::BuiltinType::Char32: |
| return "UnicodeScalar"; |
| |
| case clang::BuiltinType::Char_U: |
| case clang::BuiltinType::UChar: |
| case clang::BuiltinType::UShort: |
| case clang::BuiltinType::UInt: |
| case clang::BuiltinType::ULong: |
| case clang::BuiltinType::ULongLong: |
| case clang::BuiltinType::UInt128: |
| case clang::BuiltinType::WChar_U: |
| return getIntTypeName(false); |
| |
| case clang::BuiltinType::Char_S: |
| case clang::BuiltinType::SChar: |
| case clang::BuiltinType::Short: |
| case clang::BuiltinType::Int: |
| case clang::BuiltinType::Long: |
| case clang::BuiltinType::LongLong: |
| case clang::BuiltinType::Int128: |
| case clang::BuiltinType::WChar_S: |
| return getIntTypeName(true); |
| |
| // Types that cannot be mapped into Swift, and probably won't ever be. |
| case clang::BuiltinType::Dependent: |
| case clang::BuiltinType::ARCUnbridgedCast: |
| case clang::BuiltinType::BoundMember: |
| case clang::BuiltinType::BuiltinFn: |
| case clang::BuiltinType::Overload: |
| case clang::BuiltinType::PseudoObject: |
| case clang::BuiltinType::UnknownAny: |
| return OmissionTypeName(); |
| |
| // FIXME: Types that can be mapped, but aren't yet. |
| case clang::BuiltinType::Half: |
| case clang::BuiltinType::LongDouble: |
| case clang::BuiltinType::Float128: |
| case clang::BuiltinType::NullPtr: |
| return OmissionTypeName(); |
| |
| // Objective-C types that aren't mapped directly; rather, pointers to |
| // these types will be mapped. |
| case clang::BuiltinType::ObjCClass: |
| case clang::BuiltinType::ObjCId: |
| case clang::BuiltinType::ObjCSel: |
| return OmissionTypeName(); |
| |
| // OpenCL types that don't have Swift equivalents. |
| case clang::BuiltinType::OCLImage1dRO: |
| case clang::BuiltinType::OCLImage1dRW: |
| case clang::BuiltinType::OCLImage1dWO: |
| case clang::BuiltinType::OCLImage1dArrayRO: |
| case clang::BuiltinType::OCLImage1dArrayRW: |
| case clang::BuiltinType::OCLImage1dArrayWO: |
| case clang::BuiltinType::OCLImage1dBufferRO: |
| case clang::BuiltinType::OCLImage1dBufferRW: |
| case clang::BuiltinType::OCLImage1dBufferWO: |
| case clang::BuiltinType::OCLImage2dRO: |
| case clang::BuiltinType::OCLImage2dRW: |
| case clang::BuiltinType::OCLImage2dWO: |
| case clang::BuiltinType::OCLImage2dArrayRO: |
| case clang::BuiltinType::OCLImage2dArrayRW: |
| case clang::BuiltinType::OCLImage2dArrayWO: |
| case clang::BuiltinType::OCLImage2dDepthRO: |
| case clang::BuiltinType::OCLImage2dDepthRW: |
| case clang::BuiltinType::OCLImage2dDepthWO: |
| case clang::BuiltinType::OCLImage2dArrayDepthRO: |
| case clang::BuiltinType::OCLImage2dArrayDepthRW: |
| case clang::BuiltinType::OCLImage2dArrayDepthWO: |
| case clang::BuiltinType::OCLImage2dMSAARO: |
| case clang::BuiltinType::OCLImage2dMSAARW: |
| case clang::BuiltinType::OCLImage2dMSAAWO: |
| case clang::BuiltinType::OCLImage2dArrayMSAARO: |
| case clang::BuiltinType::OCLImage2dArrayMSAARW: |
| case clang::BuiltinType::OCLImage2dArrayMSAAWO: |
| case clang::BuiltinType::OCLImage2dMSAADepthRO: |
| case clang::BuiltinType::OCLImage2dMSAADepthRW: |
| case clang::BuiltinType::OCLImage2dMSAADepthWO: |
| case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: |
| case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: |
| case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: |
| case clang::BuiltinType::OCLImage3dRO: |
| case clang::BuiltinType::OCLImage3dRW: |
| case clang::BuiltinType::OCLImage3dWO: |
| case clang::BuiltinType::OCLSampler: |
| case clang::BuiltinType::OCLEvent: |
| case clang::BuiltinType::OCLClkEvent: |
| case clang::BuiltinType::OCLQueue: |
| case clang::BuiltinType::OCLNDRange: |
| case clang::BuiltinType::OCLReserveID: |
| return OmissionTypeName(); |
| |
| // OpenMP types that don't have Swift equivalents. |
| case clang::BuiltinType::OMPArraySection: |
| return OmissionTypeName(); |
| } |
| } |
| |
| // Tag types. |
| if (auto tagType = type->getAs<clang::TagType>()) { |
| if (tagType->getDecl()->getName().empty()) |
| return lastTypedefName; |
| |
| return tagType->getDecl()->getName(); |
| } |
| |
| // Block pointers. |
| if (type->getAs<clang::BlockPointerType>()) |
| return OmissionTypeName("Block", OmissionTypeFlags::Function); |
| |
| // Function pointers. |
| if (type->isFunctionType()) |
| return OmissionTypeName("Function", OmissionTypeFlags::Function); |
| |
| return StringRef(); |
| } |
| |
| clang::SwiftNewtypeAttr * |
| importer::getSwiftNewtypeAttr(const clang::TypedefNameDecl *decl, |
| bool useSwift2Name) { |
| // If we're determining the Swift 2 name, don't honor this attribute. |
| if (useSwift2Name) |
| return nullptr; |
| |
| // Retrieve the attribute. |
| auto attr = decl->getAttr<clang::SwiftNewtypeAttr>(); |
| if (!attr) |
| return nullptr; |
| |
| // Blacklist types that temporarily lose their |
| // swift_wrapper/swift_newtype attributes in Foundation. |
| auto name = decl->getName(); |
| if (name == "CFErrorDomain") |
| return nullptr; |
| |
| return attr; |
| } |
| |
| // If this decl is associated with a swift_newtype typedef, return it, otherwise |
| // null |
| clang::TypedefNameDecl *importer::findSwiftNewtype(const clang::NamedDecl *decl, |
| clang::Sema &clangSema, |
| bool useSwift2Name) { |
| // If we aren't honoring the swift_newtype attribute, don't even |
| // bother looking. Similarly for swift2 names |
| if (useSwift2Name) |
| return nullptr; |
| |
| auto varDecl = dyn_cast<clang::VarDecl>(decl); |
| if (!varDecl) |
| return nullptr; |
| |
| if (auto typedefTy = varDecl->getType()->getAs<clang::TypedefType>()) |
| if (getSwiftNewtypeAttr(typedefTy->getDecl(), false)) |
| return typedefTy->getDecl(); |
| |
| // Special case: "extern NSString * fooNotification" adopts |
| // NSNotificationName type, and is a member of NSNotificationName |
| if (isNSNotificationGlobal(decl)) { |
| clang::IdentifierInfo *notificationName = |
| &clangSema.getASTContext().Idents.get("NSNotificationName"); |
| clang::LookupResult lookupResult(clangSema, notificationName, |
| clang::SourceLocation(), |
| clang::Sema::LookupOrdinaryName); |
| if (!clangSema.LookupName(lookupResult, nullptr)) |
| return nullptr; |
| auto nsDecl = lookupResult.getAsSingle<clang::TypedefNameDecl>(); |
| if (!nsDecl) |
| return nullptr; |
| |
| // Make sure it also has a newtype decl on it |
| if (getSwiftNewtypeAttr(nsDecl, false)) |
| return nsDecl; |
| |
| return nullptr; |
| } |
| |
| return nullptr; |
| } |
| |
| bool importer::isNSString(const clang::Type *type) { |
| if (auto ptrType = type->getAs<clang::ObjCObjectPointerType>()) |
| if (auto interfaceType = ptrType->getInterfaceType()) |
| if (interfaceType->getDecl()->getName() == "NSString") |
| return true; |
| return false; |
| } |
| |
| bool importer::isNSString(clang::QualType qt) { |
| return qt.getTypePtrOrNull() && isNSString(qt.getTypePtrOrNull()); |
| } |
| |
| bool importer::isNSNotificationGlobal(const clang::NamedDecl *decl) { |
| // Looking for: extern NSString *fooNotification; |
| |
| // Must be extern global variable |
| auto vDecl = dyn_cast<clang::VarDecl>(decl); |
| if (!vDecl || !vDecl->hasExternalFormalLinkage()) |
| return false; |
| |
| // No explicit swift_name |
| if (decl->getAttr<clang::SwiftNameAttr>()) |
| return false; |
| |
| // Must end in Notification |
| if (!vDecl->getDeclName().isIdentifier()) |
| return false; |
| if (stripNotification(vDecl->getName()).empty()) |
| return false; |
| |
| // Must be NSString * |
| if (!isNSString(vDecl->getType())) |
| return false; |
| |
| // We're a match! |
| return true; |
| } |
| |
| bool importer::hasNativeSwiftDecl(const clang::Decl *decl) { |
| for (auto annotation : decl->specific_attrs<clang::AnnotateAttr>()) { |
| if (annotation->getAnnotation() == SWIFT_NATIVE_ANNOTATION_STRING) { |
| return true; |
| } |
| } |
| |
| if (auto *category = dyn_cast<clang::ObjCCategoryDecl>(decl)) { |
| clang::SourceLocation categoryNameLoc = category->getCategoryNameLoc(); |
| if (categoryNameLoc.isMacroID()) { |
| // Climb up to the top-most macro invocation. |
| clang::ASTContext &clangCtx = category->getASTContext(); |
| clang::SourceManager &SM = clangCtx.getSourceManager(); |
| |
| clang::SourceLocation macroCaller = |
| SM.getImmediateMacroCallerLoc(categoryNameLoc); |
| while (macroCaller.isMacroID()) { |
| categoryNameLoc = macroCaller; |
| macroCaller = SM.getImmediateMacroCallerLoc(categoryNameLoc); |
| } |
| |
| StringRef macroName = clang::Lexer::getImmediateMacroName( |
| categoryNameLoc, SM, clangCtx.getLangOpts()); |
| if (macroName == "SWIFT_EXTENSION") |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /// Translate the "nullability" notion from API notes into an optional type |
| /// kind. |
| OptionalTypeKind importer::translateNullability(clang::NullabilityKind kind) { |
| switch (kind) { |
| case clang::NullabilityKind::NonNull: |
| return OptionalTypeKind::OTK_None; |
| |
| case clang::NullabilityKind::Nullable: |
| return OptionalTypeKind::OTK_Optional; |
| |
| case clang::NullabilityKind::Unspecified: |
| return OptionalTypeKind::OTK_ImplicitlyUnwrappedOptional; |
| } |
| } |
| |
| bool importer::hasDesignatedInitializers( |
| const clang::ObjCInterfaceDecl *classDecl) { |
| if (classDecl->hasDesignatedInitializers()) |
| return true; |
| |
| return false; |
| } |
| |
| bool importer::isDesignatedInitializer( |
| const clang::ObjCInterfaceDecl *classDecl, |
| const clang::ObjCMethodDecl *method) { |
| // If the information is on the AST, use it. |
| if (classDecl->hasDesignatedInitializers()) { |
| auto *methodParent = method->getClassInterface(); |
| if (!methodParent || |
| methodParent->getCanonicalDecl() == classDecl->getCanonicalDecl()) { |
| return method->hasAttr<clang::ObjCDesignatedInitializerAttr>(); |
| } |
| } |
| |
| return false; |
| } |
| |
| bool importer::isRequiredInitializer(const clang::ObjCMethodDecl *method) { |
| // FIXME: No way to express this in Objective-C. |
| return false; |
| } |
| |
| /// Check if this method is declared in the context that conforms to |
| /// NSAccessibility. |
| static bool isAccessibilityConformingContext(const clang::DeclContext *ctx) { |
| const clang::ObjCProtocolList *protocols = nullptr; |
| |
| if (auto protocol = dyn_cast<clang::ObjCProtocolDecl>(ctx)) { |
| if (protocol->getName() == "NSAccessibility") |
| return true; |
| return false; |
| } else if (auto interface = dyn_cast<clang::ObjCInterfaceDecl>(ctx)) |
| protocols = &interface->getReferencedProtocols(); |
| else if (auto category = dyn_cast<clang::ObjCCategoryDecl>(ctx)) |
| protocols = &category->getReferencedProtocols(); |
| else |
| return false; |
| |
| for (auto pi : *protocols) { |
| if (pi->getName() == "NSAccessibility") |
| return true; |
| } |
| return false; |
| } |
| |
| bool importer::isAccessibilityDecl(const clang::Decl *decl) { |
| |
| if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(decl)) { |
| StringRef name = objCMethod->getSelector().getNameForSlot(0); |
| if (!(objCMethod->getSelector().getNumArgs() <= 1 && |
| (name.startswith("accessibility") || |
| name.startswith("setAccessibility") || |
| name.startswith("isAccessibility")))) { |
| return false; |
| } |
| |
| } else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(decl)) { |
| if (!objCProperty->getName().startswith("accessibility")) |
| return false; |
| |
| } else { |
| llvm_unreachable("The declaration is not an ObjC property or method."); |
| } |
| |
| if (isAccessibilityConformingContext(decl->getDeclContext())) |
| return true; |
| |
| return false; |
| } |
| |
| bool importer::isInitMethod(const clang::ObjCMethodDecl *method) { |
| // init methods are always instance methods. |
| if (!method->isInstanceMethod()) |
| return false; |
| |
| // init methods must be classified as such by Clang. |
| if (method->getMethodFamily() != clang::OMF_init) |
| return false; |
| |
| // Swift restriction: init methods must start with the word "init". |
| auto selector = method->getSelector(); |
| return camel_case::getFirstWord(selector.getNameForSlot(0)) == "init"; |
| } |
| |
| bool importer::isObjCId(const clang::Decl *decl) { |
| auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(decl); |
| if (!typedefDecl) |
| return false; |
| |
| if (!typedefDecl->getDeclContext()->getRedeclContext()->isTranslationUnit()) |
| return false; |
| |
| return typedefDecl->getName() == "id"; |
| } |
| |
| bool importer::isUnavailableInSwift( |
| const clang::Decl *decl, const PlatformAvailability &platformAvailability, |
| bool enableObjCInterop) { |
| // 'id' is always unavailable in Swift. |
| if (enableObjCInterop && isObjCId(decl)) |
| return true; |
| |
| // FIXME: Somewhat duplicated from importAttributes(), but this is a |
| // more direct path. |
| if (decl->getAvailability() == clang::AR_Unavailable) |
| return true; |
| |
| // Apply the deprecated-as-unavailable filter. |
| if (!platformAvailability.deprecatedAsUnavailableFilter) |
| return false; |
| |
| for (auto *attr : decl->specific_attrs<clang::AvailabilityAttr>()) { |
| if (attr->getPlatform()->getName() == "swift") |
| return true; |
| |
| if (platformAvailability.filter && |
| !platformAvailability.filter(attr->getPlatform()->getName())) { |
| continue; |
| } |
| |
| clang::VersionTuple version = attr->getDeprecated(); |
| if (version.empty()) |
| continue; |
| if (platformAvailability.deprecatedAsUnavailableFilter(version.getMajor(), |
| version.getMinor())) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| OptionalTypeKind importer::getParamOptionality(const clang::ParmVarDecl *param, |
| bool knownNonNull) { |
| auto &clangCtx = param->getASTContext(); |
| |
| // If nullability is available on the type, use it. |
| if (auto nullability = param->getType()->getNullability(clangCtx)) { |
| return translateNullability(*nullability); |
| } |
| |
| // If it's known non-null, use that. |
| if (knownNonNull || param->hasAttr<clang::NonNullAttr>()) |
| return OTK_None; |
| |
| // Default to implicitly unwrapped optionals. |
| return OTK_ImplicitlyUnwrappedOptional; |
| } |