From 6a9ccd2c2e88a2e06a9d5437f9b285d67a63e94e Mon Sep 17 00:00:00 2001 From: Vera Mitchell Date: Mon, 9 Jun 2025 09:48:38 -0600 Subject: [PATCH] distinguish between headers of the same name in different modules rdar://152676102 --- lib/SymbolGraphGen/SymbolGraphASTWalker.cpp | 17 +++++- .../ClangImporter/HeaderNameCollision.swift | 53 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/SymbolGraph/ClangImporter/HeaderNameCollision.swift diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp index cb09d846b80a7..d95185f2fea60 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp @@ -28,6 +28,21 @@ using namespace symbolgraphgen; namespace { +/// Get the fully-qualified module name of the given `ModuleDecl` as a `std::string`. +/// +/// For example, if `M` is a submodule of `ParentModule` named `SubModule`, +/// this function would return `"ParentModule.SubModule"`. +std::string getFullModuleName(const ModuleDecl *M) { + if (!M) return {}; + + std::string S; + llvm::raw_string_ostream OS(S); + + M->getReverseFullModuleName().printForward(OS); + + return S; +} + /// Compare the two \c ModuleDecl instances to see whether they are the same. /// /// This does a by-name comparison to consider a module's underlying Clang module to be equivalent @@ -36,7 +51,7 @@ namespace { /// If the `isClangEqual` argument is set to `false`, the modules must also be from the same /// compiler, i.e. a Swift module and its underlying Clang module would be considered not equal. bool areModulesEqual(const ModuleDecl *lhs, const ModuleDecl *rhs, bool isClangEqual = true) { - if (lhs->getNameStr() != rhs->getNameStr()) + if (getFullModuleName(lhs) != getFullModuleName(rhs)) return false; if (!isClangEqual && (lhs->isNonSwiftModule() != rhs->isNonSwiftModule())) diff --git a/test/SymbolGraph/ClangImporter/HeaderNameCollision.swift b/test/SymbolGraph/ClangImporter/HeaderNameCollision.swift new file mode 100644 index 0000000000000..56ba173b7a263 --- /dev/null +++ b/test/SymbolGraph/ClangImporter/HeaderNameCollision.swift @@ -0,0 +1,53 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-symbolgraph-extract -sdk %clang-importer-sdk -module-name HeaderCollision -F %t -output-dir %t -pretty-print -v +// RUN: %FileCheck %s --input-file %t/HeaderCollision.symbols.json --check-prefix MODULE +// RUN: %FileCheck %s --input-file %t/HeaderCollision@Dependency.symbols.json --check-prefix EXTENSION + +// REQUIRES: objc_interop + +// Ensure that extensions to a dependency's types, declared in a header with the same name as the +// dependency's type's header, correctly get sorted into an extension header rather than the module +// itself. + +// MODULE: "symbols": [] +// EXTENSION: "precise": "c:objc(cs)DependencyClass(im)addNumber:to:" + +//--- Dependency.framework/Modules/module.modulemap +framework module Dependency { + umbrella header "Dependency.h" + export * + module * { export * } +} + +//--- Dependency.framework/Headers/Dependency.h +#import + +//--- Dependency.framework/Headers/DependencyClass.h +@import Foundation; + +@class DependencyClass; + +@interface DependencyClass : NSObject + +@end + +//--- HeaderCollision.framework/Modules/module.modulemap +framework module HeaderCollision { + umbrella header "HeaderCollision.h" + export * + module * { export * } +} + +//--- HeaderCollision.framework/Headers/HeaderCollision.h +#import + +//--- HeaderCollision.framework/Headers/DependencyClass.h +#import + +@interface DependencyClass (HeaderCollisionClassAdditions) + +- (NSInteger)addNumber:(NSInteger)x to:(NSInteger)y; + +@end