Skip to content

Commit e909112

Browse files
committed
[PrintAsClang] refactor C function signature printer out of DeclAndTypePrinter
This will allow us to print more specific C signatures for C and C++ interop
1 parent 86f9162 commit e909112

File tree

5 files changed

+215
-13
lines changed

5 files changed

+215
-13
lines changed

lib/PrintAsClang/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ add_swift_host_library(swiftPrintAsClang STATIC
44
DeclAndTypePrinter.cpp
55
ModuleContentsWriter.cpp
66
PrimitiveTypeMapping.cpp
7-
PrintAsClang.cpp)
7+
PrintAsClang.cpp
8+
PrintClangFunction.cpp)
89
target_link_libraries(swiftPrintAsClang PRIVATE
910
swiftAST
1011
swiftClangImporter

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "DeclAndTypePrinter.h"
1414
#include "CxxSynthesis.h"
1515
#include "PrimitiveTypeMapping.h"
16+
#include "PrintClangFunction.h"
1617

1718
#include "swift/AST/ASTContext.h"
1819
#include "swift/AST/ASTMangler.h"
@@ -79,6 +80,29 @@ static bool isClangKeyword(Identifier name) {
7980
return isClangKeyword(name.str());
8081
}
8182

83+
bool DeclAndTypePrinter::isStrClangKeyword(StringRef name) {
84+
return ::isClangKeyword(name);
85+
}
86+
87+
// For a given Decl and Type, if the type is not an optional return
88+
// the type and OTK_None as the optionality. If the type is
89+
// optional, return the underlying object type, and an optionality
90+
// that is based on the type but overridden by the return value of
91+
// isImplicitlyUnwrappedOptional().
92+
std::pair<Type, OptionalTypeKind>
93+
DeclAndTypePrinter::getObjectTypeAndOptionality(const ValueDecl *D, Type ty) {
94+
OptionalTypeKind kind;
95+
if (auto objTy = ty->getReferenceStorageReferent()->getOptionalObjectType()) {
96+
kind = OTK_Optional;
97+
if (D->isImplicitlyUnwrappedOptional())
98+
kind = OTK_ImplicitlyUnwrappedOptional;
99+
100+
return {objTy, kind};
101+
}
102+
103+
return {ty, OTK_None};
104+
}
105+
82106
namespace {
83107
/// Whether the type being printed is in function param position.
84108
enum IsFunctionParam_t : bool {
@@ -285,17 +309,7 @@ class DeclAndTypePrinter::Implementation
285309
// isImplicitlyUnwrappedOptional().
286310
static std::pair<Type, OptionalTypeKind>
287311
getObjectTypeAndOptionality(const ValueDecl *D, Type ty) {
288-
OptionalTypeKind kind;
289-
if (auto objTy =
290-
ty->getReferenceStorageReferent()->getOptionalObjectType()) {
291-
kind = OTK_Optional;
292-
if (D->isImplicitlyUnwrappedOptional())
293-
kind = OTK_ImplicitlyUnwrappedOptional;
294-
295-
return {objTy, kind};
296-
}
297-
298-
return {ty, OTK_None};
312+
return DeclAndTypePrinter::getObjectTypeAndOptionality(D, ty);
299313
}
300314

301315
// Ignore other declarations.
@@ -845,7 +859,10 @@ class DeclAndTypePrinter::Implementation
845859
FuncionSwiftABIInformation funcABI(FD, mangler);
846860

847861
os << "SWIFT_EXTERN ";
848-
printFunctionDeclAsCFunctionDecl(FD, funcABI.getSymbolName(), resultTy);
862+
863+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
864+
funcPrinter.printFunctionDeclAsCFunctionDecl(FD, funcABI.getSymbolName(),
865+
resultTy);
849866
// Swift functions can't throw exceptions, we can only
850867
// throw them from C++ when emitting C++ inline thunks for the Swift
851868
// functions.

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace clang {
2626
namespace swift {
2727

2828
class PrimitiveTypeMapping;
29+
class ValueDecl;
2930

3031
/// Responsible for printing a Swift Decl or Type in Objective-C, to be
3132
/// included in a Swift module's ObjC compatibility header.
@@ -88,6 +89,12 @@ class DeclAndTypePrinter {
8889
/// Returns the name of an <os/object.h> type minus the leading "OS_",
8990
/// or an empty string if \p decl is not an <os/object.h> type.
9091
static StringRef maybeGetOSObjectBaseName(const clang::NamedDecl *decl);
92+
93+
static std::pair<Type, OptionalTypeKind>
94+
getObjectTypeAndOptionality(const ValueDecl *D, Type ty);
95+
96+
/// Returns true if \p name matches a keyword in any Clang language mode.
97+
static bool isStrClangKeyword(StringRef name);
9198
};
9299

93100
} // end namespace swift
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//===--- PrintClangFunction.cpp - Printer for C/C++ functions ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "PrintClangFunction.h"
14+
#include "DeclAndTypePrinter.h"
15+
#include "PrimitiveTypeMapping.h"
16+
#include "swift/AST/Decl.h"
17+
#include "swift/AST/ParameterList.h"
18+
#include "swift/AST/Type.h"
19+
#include "swift/AST/TypeVisitor.h"
20+
#include "swift/ClangImporter/ClangImporter.h"
21+
#include "llvm/ADT/STLExtras.h"
22+
23+
using namespace swift;
24+
25+
// Prints types in the C function signature that corresponds to the
26+
// native Swift function/method.
27+
class CFunctionSignatureTypePrinter
28+
: public TypeVisitor<CFunctionSignatureTypePrinter, void,
29+
Optional<OptionalTypeKind>> {
30+
public:
31+
CFunctionSignatureTypePrinter(raw_ostream &os,
32+
PrimitiveTypeMapping &typeMapping)
33+
: os(os), typeMapping(typeMapping) {}
34+
35+
bool printIfKnownSimpleType(const TypeDecl *typeDecl,
36+
Optional<OptionalTypeKind> optionalKind) {
37+
auto knownTypeInfo = typeMapping.getKnownObjCTypeInfo(typeDecl);
38+
if (!knownTypeInfo)
39+
return false;
40+
os << knownTypeInfo->name;
41+
// FIXME:
42+
// if (knownTypeInfo->canBeNullable)
43+
// printNullability(optionalKind);
44+
return true;
45+
}
46+
47+
void visitType(TypeBase *Ty, Optional<OptionalTypeKind> optionalKind) {
48+
assert(Ty->getDesugaredType() == Ty && "unhandled sugared type");
49+
os << "/* ";
50+
Ty->print(os);
51+
os << " */";
52+
}
53+
54+
void visitTupleType(TupleType *TT, Optional<OptionalTypeKind> optionalKind) {
55+
assert(TT->getNumElements() == 0);
56+
// FIXME: Handle non-void type.
57+
os << "void";
58+
}
59+
60+
void visitTypeAliasType(TypeAliasType *aliasTy,
61+
Optional<OptionalTypeKind> optionalKind) {
62+
const TypeAliasDecl *alias = aliasTy->getDecl();
63+
if (printIfKnownSimpleType(alias, optionalKind))
64+
return;
65+
66+
visitPart(aliasTy->getSinglyDesugaredType(), optionalKind);
67+
}
68+
69+
void visitStructType(StructType *ST,
70+
Optional<OptionalTypeKind> optionalKind) {
71+
const StructDecl *SD = ST->getStructOrBoundGenericStruct();
72+
73+
// Handle known type names.
74+
if (printIfKnownSimpleType(SD, optionalKind))
75+
return;
76+
// FIXME: Handle struct types.
77+
}
78+
79+
void visitPart(Type Ty, Optional<OptionalTypeKind> optionalKind) {
80+
TypeVisitor::visit(Ty, optionalKind);
81+
}
82+
83+
private:
84+
raw_ostream &os;
85+
PrimitiveTypeMapping &typeMapping;
86+
};
87+
88+
void DeclAndTypeClangFunctionPrinter::printFunctionDeclAsCFunctionDecl(
89+
FuncDecl *FD, StringRef name, Type resultTy) {
90+
// FIXME: Might need a PrintMultiPartType here.
91+
auto print = [this](Type ty, Optional<OptionalTypeKind> optionalKind,
92+
StringRef name) {
93+
// FIXME: add support for noescape and PrintMultiPartType,
94+
// see DeclAndTypePrinter::print.
95+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping);
96+
typePrinter.visit(ty, optionalKind);
97+
98+
if (!name.empty()) {
99+
os << ' ' << name;
100+
if (DeclAndTypePrinter::isStrClangKeyword(name))
101+
os << '_';
102+
}
103+
};
104+
105+
// Print out the return type.
106+
OptionalTypeKind kind;
107+
Type objTy;
108+
std::tie(objTy, kind) =
109+
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
110+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping);
111+
typePrinter.visit(objTy, kind);
112+
113+
os << ' ' << name << '(';
114+
115+
// Print out the parameter types.
116+
auto params = FD->getParameters();
117+
if (params->size()) {
118+
llvm::interleaveComma(*params, os, [&](const ParamDecl *param) {
119+
OptionalTypeKind kind;
120+
Type objTy;
121+
std::tie(objTy, kind) = DeclAndTypePrinter::getObjectTypeAndOptionality(
122+
param, param->getInterfaceType());
123+
StringRef paramName =
124+
param->getName().empty() ? "" : param->getName().str();
125+
print(objTy, kind, paramName);
126+
});
127+
} else {
128+
os << "void";
129+
}
130+
os << ')';
131+
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- PrintClangFunction.h - Printer for C/C++ functions -----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
14+
#define SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
15+
16+
#include "swift/AST/Type.h"
17+
#include "swift/Basic/LLVM.h"
18+
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/Support/raw_ostream.h"
20+
21+
namespace swift {
22+
23+
class FuncDecl;
24+
class PrimitiveTypeMapping;
25+
26+
/// Responsible for printing a Swift function decl or type in C or C++ mode, to
27+
/// be included in a Swift module's generated clang header.
28+
class DeclAndTypeClangFunctionPrinter {
29+
public:
30+
DeclAndTypeClangFunctionPrinter(raw_ostream &os,
31+
PrimitiveTypeMapping &typeMapping)
32+
: os(os), typeMapping(typeMapping) {}
33+
34+
/// Print the C function declaration that corresponds to the given function
35+
/// declaration.
36+
void printFunctionDeclAsCFunctionDecl(FuncDecl *FD, StringRef name,
37+
Type resultTy);
38+
39+
private:
40+
raw_ostream &os;
41+
PrimitiveTypeMapping &typeMapping;
42+
};
43+
44+
} // end namespace swift
45+
46+
#endif

0 commit comments

Comments
 (0)