Skip to content

[PrintAsClang] NFC, refactor primitive type mapping logic out from De… #41928

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/PrintAsClang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_swift_host_library(swiftPrintAsClang STATIC
CxxSynthesis.cpp
DeclAndTypePrinter.cpp
ModuleContentsWriter.cpp
PrimitiveTypeMapping.cpp
PrintAsClang.cpp)
target_link_libraries(swiftPrintAsClang PRIVATE
swiftAST
Expand Down
102 changes: 4 additions & 98 deletions lib/PrintAsClang/DeclAndTypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "DeclAndTypePrinter.h"
#include "CxxSynthesis.h"
#include "PrimitiveTypeMapping.h"

#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
Expand Down Expand Up @@ -1442,7 +1443,7 @@ class DeclAndTypePrinter::Implementation
/// Otherwise returns null.
const ClassDecl *getObjCBridgedClass(const NominalTypeDecl *nominal) {
// Print known types as their unbridged type.
if (getKnownTypeInfo(nominal))
if (owningPrinter.typeMapping.getKnownObjCTypeInfo(nominal))
return nullptr;

// Print imported bridgeable decls as their unbridged type.
Expand Down Expand Up @@ -1546,102 +1547,6 @@ class DeclAndTypePrinter::Implementation
return false;
}

/// If \p typeDecl is one of the standard library types used to map in Clang
/// primitives and basic types, return the info in \c specialNames containing
/// the Clang name and whether it can be nullable in C.
Optional<CTypeInfo> getKnownTypeInfo(const TypeDecl *typeDecl) {
auto &specialNames = owningPrinter.specialNames;
if (specialNames.empty()) {
ASTContext &ctx = getASTContext();
#define MAP(SWIFT_NAME, CLANG_REPR, NEEDS_NULLABILITY) \
specialNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = \
{ CLANG_REPR, NEEDS_NULLABILITY }

MAP(CBool, "bool", false);

MAP(CChar, "char", false);
MAP(CWideChar, "wchar_t", false);
MAP(CChar16, "char16_t", false);
MAP(CChar32, "char32_t", false);

MAP(CSignedChar, "signed char", false);
MAP(CShort, "short", false);
MAP(CInt, "int", false);
MAP(CLong, "long", false);
MAP(CLongLong, "long long", false);

MAP(CUnsignedChar, "unsigned char", false);
MAP(CUnsignedShort, "unsigned short", false);
MAP(CUnsignedInt, "unsigned int", false);
MAP(CUnsignedLong, "unsigned long", false);
MAP(CUnsignedLongLong, "unsigned long long", false);

MAP(CFloat, "float", false);
MAP(CDouble, "double", false);

MAP(Int8, "int8_t", false);
MAP(Int16, "int16_t", false);
MAP(Int32, "int32_t", false);
MAP(Int64, "int64_t", false);
MAP(UInt8, "uint8_t", false);
MAP(UInt16, "uint16_t", false);
MAP(UInt32, "uint32_t", false);
MAP(UInt64, "uint64_t", false);

MAP(Float, "float", false);
MAP(Double, "double", false);
MAP(Float32, "float", false);
MAP(Float64, "double", false);

MAP(Int, "NSInteger", false);
MAP(UInt, "NSUInteger", false);
MAP(Bool, "BOOL", false);

MAP(OpaquePointer, "void *", true);
MAP(UnsafeRawPointer, "void const *", true);
MAP(UnsafeMutableRawPointer, "void *", true);

Identifier ID_ObjectiveC = ctx.Id_ObjectiveC;
specialNames[{ID_ObjectiveC, ctx.getIdentifier("ObjCBool")}]
= { "BOOL", false};
specialNames[{ID_ObjectiveC, ctx.getIdentifier("Selector")}]
= { "SEL", true };
specialNames[{ID_ObjectiveC,
ctx.getIdentifier(
ctx.getSwiftName(KnownFoundationEntity::NSZone))}]
= { "struct _NSZone *", true };

specialNames[{ctx.Id_Darwin, ctx.getIdentifier("DarwinBoolean")}]
= { "Boolean", false};

specialNames[{ctx.Id_CoreGraphics, ctx.Id_CGFloat}]
= { "CGFloat", false };

specialNames[{ctx.Id_CoreFoundation, ctx.Id_CGFloat}]
= { "CGFloat", false };

// Use typedefs we set up for SIMD vector types.
#define MAP_SIMD_TYPE(BASENAME, _, __) \
specialNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "2")}] \
= { "swift_" #BASENAME "2", false }; \
specialNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "3")}] \
= { "swift_" #BASENAME "3", false }; \
specialNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "4")}] \
= { "swift_" #BASENAME "4", false };
#include "swift/ClangImporter/SIMDMappedTypes.def"
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
"must add or remove special name mappings if max number of "
"SIMD elements is changed");
}

Identifier moduleName = typeDecl->getModuleContext()->getName();
Identifier name = typeDecl->getName();
auto iter = specialNames.find({moduleName, name});
if (iter == specialNames.end())
return None;
return iter->second;
}

/// If \p typeDecl is one of the standard library types used to map in Clang
/// primitives and basic types, print out the appropriate spelling and
/// return true.
Expand All @@ -1650,7 +1555,8 @@ class DeclAndTypePrinter::Implementation
/// for interfacing with C and Objective-C.
bool printIfKnownSimpleType(const TypeDecl *typeDecl,
Optional<OptionalTypeKind> optionalKind) {
Optional<CTypeInfo> knownTypeInfo = getKnownTypeInfo(typeDecl);
auto knownTypeInfo =
owningPrinter.typeMapping.getKnownObjCTypeInfo(typeDecl);
if (!knownTypeInfo)
return false;
os << knownTypeInfo->name;
Expand Down
22 changes: 7 additions & 15 deletions lib/PrintAsClang/DeclAndTypePrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace clang {

namespace swift {

class PrimitiveTypeMapping;

/// Responsible for printing a Swift Decl or Type in Objective-C, to be
/// included in a Swift module's ObjC compatibility header.
class DeclAndTypePrinter {
Expand All @@ -39,22 +41,10 @@ class DeclAndTypePrinter {
raw_ostream &os;
raw_ostream &prologueOS;
const DelayedMemberSet &delayedMembers;
PrimitiveTypeMapping &typeMapping;
AccessLevel minRequiredAccess;
OutputLanguageMode outputLang;

struct CTypeInfo {
StringRef name;
bool canBeNullable;
};

/// A map from {Module, TypeName} pairs to {C name, C nullability} pairs.
///
/// This is populated on first use with a list of known Swift types that are
/// translated directly by the ObjC printer instead of structurally, allowing
/// it to do things like map 'Int' to 'NSInteger' and 'Float' to 'float'.
/// In some sense it's the reverse of the ClangImporter's MappedTypes.def.
llvm::DenseMap<std::pair<Identifier, Identifier>, CTypeInfo> specialNames;

/// The name 'CFTypeRef'.
///
/// Cached for convenience.
Expand All @@ -64,10 +54,12 @@ class DeclAndTypePrinter {

public:
DeclAndTypePrinter(ModuleDecl &mod, raw_ostream &out, raw_ostream &prologueOS,
DelayedMemberSet &delayed, AccessLevel access,
DelayedMemberSet &delayed,
PrimitiveTypeMapping &typeMapping, AccessLevel access,
OutputLanguageMode outputLang)
: M(mod), os(out), prologueOS(prologueOS), delayedMembers(delayed),
minRequiredAccess(access), outputLang(outputLang) {}
typeMapping(typeMapping), minRequiredAccess(access),
outputLang(outputLang) {}

/// Returns true if \p VD should be included in a compatibility header for
/// the options the printer was constructed with.
Expand Down
5 changes: 4 additions & 1 deletion lib/PrintAsClang/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "CxxSynthesis.h"
#include "DeclAndTypePrinter.h"
#include "OutputLanguageMode.h"
#include "PrimitiveTypeMapping.h"

#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Module.h"
Expand Down Expand Up @@ -123,6 +124,7 @@ class ModuleWriter {
llvm::DenseMap<const TypeDecl *, std::pair<EmissionState, bool>> seenTypes;
std::vector<const Decl *> declsToWrite;
DelayedMemberSet delayedMembers;
PrimitiveTypeMapping typeMapping;
DeclAndTypePrinter printer;
OutputLanguageMode outputLangMode;

Expand All @@ -131,7 +133,8 @@ class ModuleWriter {
llvm::SmallPtrSetImpl<ImportModuleTy> &imports, ModuleDecl &mod,
AccessLevel access, OutputLanguageMode outputLang)
: os(os), imports(imports), M(mod),
printer(M, os, prologueOS, delayedMembers, access, outputLang),
printer(M, os, prologueOS, delayedMembers, typeMapping, access,
outputLang),
outputLangMode(outputLang) {}

/// Returns true if we added the decl's module to the import set, false if
Expand Down
112 changes: 112 additions & 0 deletions lib/PrintAsClang/PrimitiveTypeMapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//===--- PrimitiveTypeMapping.cpp - Mapping primitive types -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "PrimitiveTypeMapping.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/ClangImporter/ClangImporter.h"

using namespace swift;

void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
assert(mappedTypeNames.empty() && "expected empty type map");
#define MAP(SWIFT_NAME, CLANG_REPR, NEEDS_NULLABILITY) \
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
CLANG_REPR, NEEDS_NULLABILITY}

MAP(CBool, "bool", false);

MAP(CChar, "char", false);
MAP(CWideChar, "wchar_t", false);
MAP(CChar16, "char16_t", false);
MAP(CChar32, "char32_t", false);

MAP(CSignedChar, "signed char", false);
MAP(CShort, "short", false);
MAP(CInt, "int", false);
MAP(CLong, "long", false);
MAP(CLongLong, "long long", false);

MAP(CUnsignedChar, "unsigned char", false);
MAP(CUnsignedShort, "unsigned short", false);
MAP(CUnsignedInt, "unsigned int", false);
MAP(CUnsignedLong, "unsigned long", false);
MAP(CUnsignedLongLong, "unsigned long long", false);

MAP(CFloat, "float", false);
MAP(CDouble, "double", false);

MAP(Int8, "int8_t", false);
MAP(Int16, "int16_t", false);
MAP(Int32, "int32_t", false);
MAP(Int64, "int64_t", false);
MAP(UInt8, "uint8_t", false);
MAP(UInt16, "uint16_t", false);
MAP(UInt32, "uint32_t", false);
MAP(UInt64, "uint64_t", false);

MAP(Float, "float", false);
MAP(Double, "double", false);
MAP(Float32, "float", false);
MAP(Float64, "double", false);

MAP(Int, "NSInteger", false);
MAP(UInt, "NSUInteger", false);
MAP(Bool, "BOOL", false);

MAP(OpaquePointer, "void *", true);
MAP(UnsafeRawPointer, "void const *", true);
MAP(UnsafeMutableRawPointer, "void *", true);

Identifier ID_ObjectiveC = ctx.Id_ObjectiveC;
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("ObjCBool")}] = {"BOOL",
false};
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("Selector")}] = {"SEL",
true};
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier(ctx.getSwiftName(
KnownFoundationEntity::NSZone))}] = {
"struct _NSZone *", true};

mappedTypeNames[{ctx.Id_Darwin, ctx.getIdentifier("DarwinBoolean")}] = {
"Boolean", false};

mappedTypeNames[{ctx.Id_CoreGraphics, ctx.Id_CGFloat}] = {"CGFloat", false};

mappedTypeNames[{ctx.Id_CoreFoundation, ctx.Id_CGFloat}] = {"CGFloat", false};

// Use typedefs we set up for SIMD vector types.
#define MAP_SIMD_TYPE(BASENAME, _, __) \
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "2")}] = { \
"swift_" #BASENAME "2", false}; \
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "3")}] = { \
"swift_" #BASENAME "3", false}; \
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "4")}] = { \
"swift_" #BASENAME "4", false};
#include "swift/ClangImporter/SIMDMappedTypes.def"
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
"must add or remove special name mappings if max number of "
"SIMD elements is changed");
}

Optional<PrimitiveTypeMapping::ObjCClangTypeInfo>
PrimitiveTypeMapping::getKnownObjCTypeInfo(const TypeDecl *typeDecl) {
if (mappedTypeNames.empty())
initialize(typeDecl->getASTContext());

Identifier moduleName = typeDecl->getModuleContext()->getName();
Identifier name = typeDecl->getName();
auto iter = mappedTypeNames.find({moduleName, name});
if (iter == mappedTypeNames.end())
return None;
return ObjCClangTypeInfo{iter->second.objcName, iter->second.canBeNullable};
}
63 changes: 63 additions & 0 deletions lib/PrintAsClang/PrimitiveTypeMapping.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===--- PrimitiveTypeMapping.h - Mapping primitive types -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_PRINTASCLANG_PRIMITIVETYPEMAPPING_H
#define SWIFT_PRINTASCLANG_PRIMITIVETYPEMAPPING_H

#include "swift/AST/Identifier.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"

namespace swift {

class ASTContext;
class TypeDecl;

/// Provides a mapping from Swift's primitive types to C / Objective-C / C++
/// primitive types.
///
/// Certain types have mappings that differ in different language modes.
/// For example, Swift's `Int` maps to `NSInteger` for Objective-C declarations,
/// but to something like `intptr_t` or `swift::Int` for C and C++ declarations.
class PrimitiveTypeMapping {
public:
struct ObjCClangTypeInfo {
StringRef name;
bool canBeNullable;
};

/// Returns the Objective-C type name and nullability for the given Swift
/// primitive type declaration, or \c None if no such type name exists.
Optional<ObjCClangTypeInfo> getKnownObjCTypeInfo(const TypeDecl *typeDecl);

private:
void initialize(ASTContext &ctx);

struct ClangTypeInfo {
// The Objective-C name of the Swift type.
StringRef objcName;
bool canBeNullable;
};

/// A map from {Module, TypeName} pairs to {C name, C nullability} pairs.
///
/// This is populated on first use with a list of known Swift types that are
/// translated directly by the ObjC printer instead of structurally, allowing
/// it to do things like map 'Int' to 'NSInteger' and 'Float' to 'float'.
/// In some sense it's the reverse of the ClangImporter's MappedTypes.def.
llvm::DenseMap<std::pair<Identifier, Identifier>, ClangTypeInfo>
mappedTypeNames;
};

} // end namespace swift

#endif