Skip to content

Commit 0aff85c

Browse files
committed
Emit mangled names for public symbols into the .swiftinterface
When the frontend option `-abi-comments-in-module-interface` is provided during interface printing, the printed interface will contain additional comments that provide the mangled names for public symbols. This is an experiment in seeing how much information we can meaningfully extract from a printed Swift interface for the purpose of bridging with other languages.
1 parent 77ed014 commit 0aff85c

File tree

7 files changed

+107
-13
lines changed

7 files changed

+107
-13
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,10 @@ struct PrintOptions {
520520
/// with types sharing a name with a module.
521521
bool AliasModuleNames = false;
522522

523+
/// Print some ABI details for public symbols as comments that can be
524+
/// parsed by another tool.
525+
bool PrintABIComments = false;
526+
523527
/// Name of the modules that have been aliased in AliasModuleNames mode.
524528
/// Ideally we would use something other than a string to identify a module,
525529
/// but since one alias can apply to more than one module, strings happen
@@ -707,7 +711,8 @@ struct PrintOptions {
707711
bool useExportedModuleNames,
708712
bool aliasModuleNames,
709713
llvm::SmallSet<StringRef, 4>
710-
*aliasModuleNamesTargets
714+
*aliasModuleNamesTargets,
715+
bool abiComments
711716
);
712717

713718
/// Retrieve the set of options suitable for "Generated Interfaces", which

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ struct ModuleInterfaceOptions {
4242
/// [TODO: Clang-type-plumbing] This check should go away.
4343
bool PrintFullConvention = false;
4444

45+
/// Print some ABI details for public symbols as comments that can be
46+
/// parsed by another tool.
47+
bool ABIComments = false;
48+
4549
struct InterfaceFlags {
4650
/// Copy of all the command-line flags passed at .swiftinterface
4751
/// generation time, re-applied to CompilerInvocation when reading

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,9 @@ def disable_alias_module_names_in_module_interface :
10491049
Flag<["-"], "disable-alias-module-names-in-module-interface">,
10501050
HelpText<"When emitting a module interface, disable disambiguating modules "
10511051
"using distinct alias names">;
1052+
def abi_comments_in_module_interface :
1053+
Flag<["-"], "abi-comments-in-module-interface">,
1054+
HelpText<"When emitting a module interface, emit comments with ABI details">;
10521055

10531056
def experimental_spi_imports :
10541057
Flag<["-"], "experimental-spi-imports">,

lib/AST/ASTPrinter.cpp

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
207207
bool useExportedModuleNames,
208208
bool aliasModuleNames,
209209
llvm::SmallSet<StringRef, 4>
210-
*aliasModuleNamesTargets
211-
) {
210+
*aliasModuleNamesTargets,
211+
bool abiComments) {
212212
PrintOptions result;
213213
result.IsForSwiftInterface = true;
214214
result.PrintLongAttrsOnSeparateLines = true;
@@ -230,6 +230,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
230230
result.PreferTypeRepr = preferTypeRepr;
231231
result.AliasModuleNames = aliasModuleNames;
232232
result.AliasModuleNamesTargets = aliasModuleNamesTargets;
233+
result.PrintABIComments = abiComments;
233234
if (printFullConvention)
234235
result.PrintFunctionRepresentationAttrs =
235236
PrintOptions::FunctionRepresentationMode::Full;
@@ -770,19 +771,28 @@ class PrintAST : public ASTVisitor<PrintAST> {
770771
printRawComment(RC);
771772
}
772773

774+
/// If we should print a mangled name for this declaration, return that
775+
/// mangled name.
776+
std::optional<std::string> mangledNameToPrint(const Decl *D);
777+
773778
void printDocumentationComment(const Decl *D) {
774-
if (!Options.PrintDocumentationComments)
775-
return;
779+
if (Options.PrintDocumentationComments) {
780+
// Try to print a comment from Clang.
781+
auto MaybeClangNode = D->getClangNode();
782+
if (MaybeClangNode) {
783+
if (auto *CD = MaybeClangNode.getAsDecl())
784+
printClangDocumentationComment(CD);
785+
return;
786+
}
776787

777-
// Try to print a comment from Clang.
778-
auto MaybeClangNode = D->getClangNode();
779-
if (MaybeClangNode) {
780-
if (auto *CD = MaybeClangNode.getAsDecl())
781-
printClangDocumentationComment(CD);
782-
return;
788+
printSwiftDocumentationComment(D);
783789
}
784790

785-
printSwiftDocumentationComment(D);
791+
if (auto mangledName = mangledNameToPrint(D)) {
792+
indent();
793+
Printer << "// MANGLED NAME: " << *mangledName;
794+
Printer.printNewline();
795+
}
786796
}
787797

788798
void printStaticKeyword(StaticSpellingKind StaticSpelling) {
@@ -3061,6 +3071,60 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
30613071
}
30623072
}
30633073

3074+
std::optional<std::string> PrintAST::mangledNameToPrint(const Decl *D) {
3075+
using ASTMangler = Mangle::ASTMangler;
3076+
3077+
if (!Options.PrintABIComments)
3078+
return std::nullopt;
3079+
3080+
auto valueDecl = dyn_cast<ValueDecl>(D);
3081+
if (!valueDecl)
3082+
return std::nullopt;
3083+
3084+
// Anything with an access level less than "package" isn't meant to be
3085+
// referenced from source code outside the module.
3086+
if (valueDecl->getEffectiveAccess() < AccessLevel::Package)
3087+
return std::nullopt;
3088+
3089+
// For functions, mangle the entity directly.
3090+
if (auto func = dyn_cast<FuncDecl>(D)) {
3091+
ASTMangler mangler;
3092+
return mangler.mangleEntity(func);
3093+
}
3094+
3095+
// For initializers, mangle the allocating initializer.
3096+
if (auto init = dyn_cast<ConstructorDecl>(D)) {
3097+
ASTMangler mangler;
3098+
return mangler.mangleConstructorEntity(init, /*isAllocating=*/true);
3099+
}
3100+
3101+
// For global and static variables, mangle the entity directly.
3102+
if (auto var = dyn_cast<VarDecl>(D)) {
3103+
if (!var->isInstanceMember()) {
3104+
ASTMangler mangler;
3105+
return mangler.mangleEntity(var);
3106+
}
3107+
}
3108+
3109+
// For subscripts, mangle the entity directly.
3110+
if (auto subscript = dyn_cast<SubscriptDecl>(D)) {
3111+
ASTMangler mangler;
3112+
return mangler.mangleEntity(subscript);
3113+
}
3114+
3115+
// For nominal types, mangle the type metadata accessor.
3116+
if (auto nominal = dyn_cast<NominalTypeDecl>(D)) {
3117+
if (!isa<ProtocolDecl>(nominal) && !nominal->getGenericSignature()) {
3118+
ASTMangler mangler;
3119+
std::string name = mangler.mangleNominalType(nominal);
3120+
name += "Ma";
3121+
return name;
3122+
}
3123+
}
3124+
3125+
return std::nullopt;
3126+
}
3127+
30643128
static void suppressingFeatureIsolatedAny(PrintOptions &options,
30653129
llvm::function_ref<void()> action) {
30663130
llvm::SaveAndRestore<bool> scope(options.SuppressIsolatedAny, true);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
525525
Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax);
526526
Opts.PrintMissingImports =
527527
!Args.hasArg(OPT_disable_print_missing_imports_in_module_interface);
528+
Opts.ABIComments = Args.hasArg(OPT_abi_comments_in_module_interface);
528529

529530
if (const Arg *A = Args.getLastArg(OPT_library_level)) {
530531
StringRef contents = A->getValue();

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ bool swift::emitSwiftInterface(raw_ostream &out,
914914
M, Opts.PreserveTypesAsWritten, Opts.PrintFullConvention,
915915
Opts.InterfaceContentMode,
916916
useExportedModuleNames,
917-
Opts.AliasModuleNames, &aliasModuleNamesTargets);
917+
Opts.AliasModuleNames, &aliasModuleNamesTargets, Opts.ABIComments);
918918
InheritedProtocolCollector::PerTypeMap inheritedProtocolMap;
919919

920920
SmallVector<Decl *, 16> topLevelDecls;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t/ABIComments.swiftinterface -module-name ABIComments -abi-comments-in-module-interface %s
4+
5+
// RUN: %FileCheck %s < %t/ABIComments.swiftinterface
6+
7+
// CHECK: // MANGLED NAME: $s11ABIComments11intToStringySSSiF
8+
// CHECK-NEXT: public func intToString(_ value: Swift.Int) -> Swift.String
9+
public func intToString(_ value: Int) -> String { "\(value)" }
10+
11+
// CHECK: // MANGLED NAME: $s11ABIComments8MyStructVMa
12+
// CHECK-NEXT: public struct MyStruct {
13+
public struct MyStruct {
14+
// CHECK: // MANGLED NAME: $s11ABIComments8MyStructV6methodSiyF
15+
// CHECK-NEXT: public func method() -> Swift.Int
16+
public func method() -> Int { 5 }
17+
}

0 commit comments

Comments
 (0)