From fb4883e47e8ed0ad87ec6ac6d4f089800f10221e Mon Sep 17 00:00:00 2001 From: Dylan Sturgeon Date: Mon, 8 Dec 2025 14:19:06 -0800 Subject: [PATCH] Store the name of the extended module in the symbolgraph module representation. The extended module's name is typically extracted from the filename of the symbolgraph. This approach is problematic for modules with long names, because the filename "ModuleA@ModuleB" can exceed the limits for filepath segments on common file systems, e.g. there's a limit of 255 on macOS. This root problem has an opt-in workaround now, with the changes in https://github.com/swiftlang/swift/pull/83782 to support a new option "symbol-graph-shorten-output-names". But that approach alone leaves swift-docc-symbolkit in a tough spot to handle the alternative naming convention. It would be nice to also support the symbolgraph files of modules with long names in swift-docc-symbolkit. That library extracts the name of the symbolgraph's module to use for merging declarations in the same module. In some modes, extensions are merged with declarations from the extended module instead of the declaring module. When generating symbolgraphs with `-symbol-graph-shorten-output-names`, swift-docc-symbolkit cannot determine the extended module name. There appears to be 2 options to solve this: (A) propagate the rename map file throughout symbolkit and its callers to lookup the extended module's name as needed, or (B) store the extended module in the symbolgraph JSON representation. This change enables option B. This option reduces the complexity of changes in swift-docc-symbolkit, while allowing simple backwards compatibility by defaulting to the current "Module@Extended" naming scheme. --- lib/SymbolGraphGen/FormatVersion.h | 2 +- lib/SymbolGraphGen/SymbolGraph.cpp | 14 ++++++++++++-- test/SymbolGraph/Module/BasicExtension.swift | 1 + test/SymbolGraph/Module/Module.swift | 1 + test/SymbolGraph/Module/NestedExtensions.swift | 1 + 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/SymbolGraphGen/FormatVersion.h b/lib/SymbolGraphGen/FormatVersion.h index 4702e8dad03d1..b7a032fe6d970 100644 --- a/lib/SymbolGraphGen/FormatVersion.h +++ b/lib/SymbolGraphGen/FormatVersion.h @@ -14,7 +14,7 @@ #define SWIFT_SYMBOLGRAPHGEN_FORMATVERSION_H #define SWIFT_SYMBOLGRAPH_FORMAT_MAJOR 0 -#define SWIFT_SYMBOLGRAPH_FORMAT_MINOR 6 +#define SWIFT_SYMBOLGRAPH_FORMAT_MINOR 7 #define SWIFT_SYMBOLGRAPH_FORMAT_PATCH 0 #endif // SWIFT_SYMBOLGRAPHGEN_FORMATVERSION_H diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index 8866920421a76..f2be31da05ca1 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -624,16 +624,26 @@ void SymbolGraph::serialize(llvm::json::OStream &OS) { }); // end metadata: OS.attributeObject("module", [&](){ + std::string ModuleName; if (DeclaringModule) { // A cross-import overlay can be considered part of its declaring module - OS.attribute("name", getFullModuleName(*DeclaringModule)); + ModuleName = getFullModuleName(*DeclaringModule); + OS.attribute("name", ModuleName); std::vector B; for (auto BModule : BystanderModules) { B.push_back(BModule.str()); } OS.attribute("bystanders", B); } else { - OS.attribute("name", getFullModuleName(&M)); + ModuleName = getFullModuleName(&M); + OS.attribute("name", ModuleName); + } + if (ExtendedModule) { + OS.attribute("extended", getFullModuleName(*ExtendedModule)); + } else { + // When the symbol graph isn't extending another module, signal that to the reader by + // repeating the source module's name. + OS.attribute("extended", ModuleName); } AttributeRAII Platform("platform", OS); diff --git a/test/SymbolGraph/Module/BasicExtension.swift b/test/SymbolGraph/Module/BasicExtension.swift index 828df4e314175..4e386bea2f18d 100644 --- a/test/SymbolGraph/Module/BasicExtension.swift +++ b/test/SymbolGraph/Module/BasicExtension.swift @@ -35,6 +35,7 @@ extension String { // ALL-LABEL: module // ALL: {{"name": ?"BasicExtension"}} +// ALL: {{"extended": ?"Swift"}} // Check for Symbols and Documentation Strings: diff --git a/test/SymbolGraph/Module/Module.swift b/test/SymbolGraph/Module/Module.swift index 4ebc350b03485..0411d05ae0101 100644 --- a/test/SymbolGraph/Module/Module.swift +++ b/test/SymbolGraph/Module/Module.swift @@ -8,6 +8,7 @@ public struct S { // CHECK: module // CHECK-NEXT: "name": "SymbolGraphModule" +// CHECK-NEXT: "extended": "SymbolGraphModule" // CHECK-NEXT: platform // CHECK-NEXT: architecture // CHECK: vendor diff --git a/test/SymbolGraph/Module/NestedExtensions.swift b/test/SymbolGraph/Module/NestedExtensions.swift index cbc37d7298693..03df614e0ffa4 100644 --- a/test/SymbolGraph/Module/NestedExtensions.swift +++ b/test/SymbolGraph/Module/NestedExtensions.swift @@ -46,5 +46,6 @@ extension AStruct.BStruct.CStruct where Thing: Equatable { // NESTED-NOT: BStruct // NESTED-NOT: CStruct // NESTED-NOT: "swift.extension" +// NESTEDATA-DAG: "extended": "A" // NESTEDATA-DAG: "precise": "s:1A7AStructV1BE7BStructV16NestedExtensionsE7CStructV" // NESTEDATA-DAG: "precise": "s:e:s:1A7AStructV1BE7BStructV16NestedExtensionsE7CStructV"