Skip to content

Commit 5f851b6

Browse files
authored
Merge pull request #76065 from augusto2112/clash-abi-name-demangler
Account for multiple modules when looking up the DeclContext of a type
2 parents b0b5b2a + 141c96f commit 5f851b6

File tree

8 files changed

+221
-46
lines changed

8 files changed

+221
-46
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,10 +1224,15 @@ class ASTContext final {
12241224

12251225
ModuleDecl *getModuleByIdentifier(Identifier ModuleID);
12261226

1227-
/// Looks up an already loaded module by its ABI name.
1227+
/// Looks up all modules whose real name or ABI name match ModuleName.
12281228
///
1229-
/// \returns The module if found, nullptr otherwise.
1230-
ModuleDecl *getLoadedModuleByABIName(StringRef ModuleName);
1229+
/// Modules that are being looked up by ABI name are only found if they are a
1230+
/// dependency of a module that has that same name as its real name, as there
1231+
/// is no efficient way to lazily load a module by ABI name.
1232+
llvm::ArrayRef<ModuleDecl *> getModulesByRealOrABIName(StringRef ModuleName);
1233+
1234+
/// Notifies the AST context that a loaded module's ABI name will change.
1235+
void moduleABINameWillChange(ModuleDecl *module, Identifier newName);
12311236

12321237
/// Returns the standard library module, or null if the library isn't present.
12331238
///

include/swift/AST/ASTDemangler.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,13 @@ class ASTBuilder {
258258
NominalTypeDecl *nominalDecl,
259259
NodePointer node);
260260
DeclContext *findDeclContext(NodePointer node);
261-
ModuleDecl *findModule(NodePointer node);
261+
262+
/// Find all the ModuleDecls that correspond to a module node's identifier.
263+
/// The module name encoded in the node is either the module's real or ABI
264+
/// name. Multiple modules can share the same name. This function returns
265+
/// all modules that contain that name.
266+
llvm::ArrayRef<ModuleDecl *> findPotentialModules(NodePointer node);
267+
262268
Demangle::NodePointer findModuleNode(NodePointer node);
263269

264270
enum class ForeignModuleKind {

include/swift/AST/Module.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,7 @@ class ModuleDecl
473473
Identifier getABIName() const;
474474

475475
/// Set the ABI name of the module;
476-
void setABIName(Identifier name) {
477-
ModuleABIName = name;
478-
}
476+
void setABIName(Identifier name);
479477

480478
/// Get the package name of this module
481479
/// FIXME: remove this and bump module version rdar://104723918

lib/AST/ASTContext.cpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ struct ASTContext::Implementation {
276276
/// DenseMap.
277277
llvm::MapVector<Identifier, ModuleDecl *> LoadedModules;
278278

279+
/// The map from a module's name to a vector of modules that share that name.
280+
/// The name can be either the module's real name of the module's ABI name.
281+
llvm::DenseMap<Identifier, llvm::SmallVector<ModuleDecl *, 1>> NameToModules;
282+
279283
// FIXME: This is a StringMap rather than a StringSet because StringSet
280284
// doesn't allow passing in a pre-existing allocator.
281285
llvm::StringMap<Identifier::Aligner, llvm::BumpPtrAllocator&>
@@ -839,6 +843,7 @@ void ASTContext::Implementation::dump(llvm::raw_ostream &os) const {
839843
<< llvm::capacity_in_bytes(Name) << "\n"
840844

841845
SIZE(LoadedModules);
846+
SIZE(NameToModules);
842847
SIZE(IdentifierTable);
843848
SIZE(Cleanups);
844849
SIZE_AND_BYTES(ModuleLoaders);
@@ -2322,12 +2327,63 @@ void ASTContext::addLoadedModule(ModuleDecl *M) {
23222327
// and a source file has 'import Foo', a module called Bar (real name)
23232328
// will be loaded and added to the map.
23242329
getImpl().LoadedModules[M->getRealName()] = M;
2330+
2331+
// Add the module to the mapping from module name to list of modules that
2332+
// share that name.
2333+
getImpl().NameToModules[M->getRealName()].push_back(M);
2334+
2335+
// If the ABI name differs from the real name, also add the module to the list
2336+
// that share that ABI name.
2337+
if (M->getRealName() != M->getABIName())
2338+
getImpl().NameToModules[M->getABIName()].push_back(M);
23252339
}
23262340

23272341
void ASTContext::removeLoadedModule(Identifier RealName) {
2342+
// First remove the module from the mappings of names to modules.
2343+
if (ModuleDecl *M = getLoadedModule(RealName)) {
2344+
auto eraseModule = [&](ModuleDecl *module) {
2345+
return module->getRealName() == RealName;
2346+
};
2347+
auto &vector = getImpl().NameToModules[M->getRealName()];
2348+
llvm::erase_if(vector, eraseModule);
2349+
if (M->getRealName() != M->getABIName()) {
2350+
auto &vector = getImpl().NameToModules[M->getABIName()];
2351+
llvm::erase_if(vector, eraseModule);
2352+
}
2353+
}
2354+
23282355
getImpl().LoadedModules.erase(RealName);
23292356
}
23302357

2358+
void ASTContext::moduleABINameWillChange(ModuleDecl *module,
2359+
Identifier newName) {
2360+
auto it = llvm::find_if(getLoadedModules(),
2361+
[&](auto pair) { return pair.second == module; });
2362+
2363+
// If this module isn't in the loaded modules list (perhaps because there is
2364+
// no memory cache) theere's nothing to do.
2365+
if (it == getLoadedModules().end())
2366+
return;
2367+
2368+
// If the names are the same there's nothing to do.
2369+
if (module->getABIName() == newName)
2370+
return;
2371+
2372+
// If the real and ABI names are different, ASTContext needs to remove the
2373+
// module from the mapping whose key is the old ABI name.
2374+
if (module->getRealName() != module->getABIName()) {
2375+
auto &vector = getImpl().NameToModules[module->getABIName()];
2376+
llvm::erase_if(vector,
2377+
[&](ModuleDecl *current) { return module == current; });
2378+
}
2379+
2380+
// Now add the module to the vector that's mapped from the new name, if it's
2381+
// not there already.
2382+
auto &vector = getImpl().NameToModules[newName];
2383+
if (llvm::find(vector, module) == vector.end())
2384+
vector.push_back(module);
2385+
}
2386+
23312387
void ASTContext::setIgnoreAdjacentModules(bool value) {
23322388
IgnoreAdjacentModules = value;
23332389
}
@@ -2714,12 +2770,21 @@ ModuleDecl *ASTContext::getModuleByIdentifier(Identifier ModuleID) {
27142770
return getModule(builder.get());
27152771
}
27162772

2717-
ModuleDecl *ASTContext::getLoadedModuleByABIName(StringRef ModuleName) {
2718-
for (auto &[_, module] : getLoadedModules()) {
2719-
if (ModuleName == module->getABIName().str())
2720-
return module;
2721-
}
2722-
return nullptr;
2773+
llvm::ArrayRef<ModuleDecl *>
2774+
ASTContext::getModulesByRealOrABIName(StringRef ModuleName) {
2775+
auto Identifier = getIdentifier(ModuleName);
2776+
auto it = getImpl().NameToModules.find(Identifier);
2777+
if (it != getImpl().NameToModules.end())
2778+
return it->second;
2779+
2780+
// If we didn't find the module it might have not been loaded yet, try
2781+
// triggering a module load and searching again.
2782+
getModuleByName(ModuleName);
2783+
it = getImpl().NameToModules.find(Identifier);
2784+
if (it != getImpl().NameToModules.end())
2785+
return it->second;
2786+
2787+
return {};
27232788
}
27242789

27252790
ModuleDecl *ASTContext::getStdlibModule(bool loadIfAbsent) {

lib/AST/ASTDemangler.cpp

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,15 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
264264
auto moduleNode = findModuleNode(definingDecl);
265265
if (!moduleNode)
266266
return Type();
267-
auto parentModule = findModule(moduleNode);
268-
if (!parentModule)
267+
auto potentialParentModules = findPotentialModules(moduleNode);
268+
if (potentialParentModules.empty())
269269
return Type();
270270

271-
auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName);
271+
OpaqueTypeDecl *opaqueDecl = nullptr;
272+
for (auto module : potentialParentModules)
273+
if (auto decl = module->lookupOpaqueResultType(mangledName))
274+
opaqueDecl = decl;
275+
272276
if (!opaqueDecl)
273277
return Type();
274278
SmallVector<Type, 8> allArgs;
@@ -1129,17 +1133,11 @@ ASTBuilder::createTypeDecl(NodePointer node,
11291133
return dyn_cast<GenericTypeDecl>(DC);
11301134
}
11311135

1132-
ModuleDecl *ASTBuilder::findModule(NodePointer node) {
1136+
llvm::ArrayRef<ModuleDecl *>
1137+
ASTBuilder::findPotentialModules(NodePointer node) {
11331138
assert(node->getKind() == Demangle::Node::Kind::Module);
11341139
const auto moduleName = node->getText();
1135-
// Respect the module's ABI name when we're trying to resolve
1136-
// mangled names. But don't touch anything under the Swift stdlib's
1137-
// umbrella.
1138-
if (moduleName != STDLIB_NAME)
1139-
if (auto *Module = Ctx.getLoadedModuleByABIName(moduleName))
1140-
return Module;
1141-
1142-
return Ctx.getModuleByName(moduleName);
1140+
return Ctx.getModulesByRealOrABIName(moduleName);
11431141
}
11441142

11451143
Demangle::NodePointer
@@ -1229,8 +1227,17 @@ ASTBuilder::findDeclContext(NodePointer node) {
12291227
case Demangle::Node::Kind::BoundGenericTypeAlias:
12301228
return findDeclContext(node->getFirstChild());
12311229

1232-
case Demangle::Node::Kind::Module:
1233-
return findModule(node);
1230+
case Demangle::Node::Kind::Module: {
1231+
// A Module node is not enough information to find the decl context.
1232+
// The reason being that the module name in a mangled name can either be
1233+
// the module's ABI name, which is potentially not unique (due to the
1234+
// -module-abi-name flag), or the module's real name, if mangling for the
1235+
// debugger or USR together with the OriginallyDefinedIn attribute for
1236+
// example.
1237+
assert(false && "Looked up module as decl context directly!");
1238+
auto modules = findPotentialModules(node);
1239+
return modules.empty() ? nullptr : modules[0];
1240+
}
12341241

12351242
case Demangle::Node::Kind::Class:
12361243
case Demangle::Node::Kind::Enum:
@@ -1243,20 +1250,24 @@ ASTBuilder::findDeclContext(NodePointer node) {
12431250
if (declNameNode->getKind() == Demangle::Node::Kind::LocalDeclName) {
12441251
// Find the AST node for the defining module.
12451252
auto moduleNode = findModuleNode(node);
1246-
if (!moduleNode) return nullptr;
1253+
if (!moduleNode)
1254+
return nullptr;
12471255

1248-
auto module = findModule(moduleNode);
1249-
if (!module) return nullptr;
1256+
auto potentialModules = findPotentialModules(moduleNode);
1257+
if (potentialModules.empty())
1258+
return nullptr;
12501259

12511260
// Look up the local type by its mangling.
12521261
auto mangling = Demangle::mangleNode(node);
1253-
if (!mangling.isSuccess()) return nullptr;
1262+
if (!mangling.isSuccess())
1263+
return nullptr;
12541264
auto mangledName = mangling.result();
12551265

1256-
auto decl = module->lookupLocalType(mangledName);
1257-
if (!decl) return nullptr;
1266+
for (auto *module : potentialModules)
1267+
if (auto *decl = module->lookupLocalType(mangledName))
1268+
return dyn_cast<DeclContext>(decl);
12581269

1259-
return dyn_cast<DeclContext>(decl);
1270+
return nullptr;
12601271
}
12611272

12621273
StringRef name;
@@ -1290,22 +1301,33 @@ ASTBuilder::findDeclContext(NodePointer node) {
12901301
}
12911302
}
12921303

1293-
DeclContext *dc = findDeclContext(node->getChild(0));
1294-
if (!dc) {
1304+
auto child = node->getFirstChild();
1305+
if (child->getKind() == Node::Kind::Module) {
1306+
auto potentialModules = findPotentialModules(child);
1307+
if (potentialModules.empty())
1308+
return nullptr;
1309+
1310+
for (auto *module : potentialModules)
1311+
if (auto typeDecl = findTypeDecl(module, Ctx.getIdentifier(name),
1312+
privateDiscriminator, node->getKind()))
1313+
return typeDecl;
12951314
return nullptr;
12961315
}
12971316

1298-
return findTypeDecl(dc, Ctx.getIdentifier(name),
1299-
privateDiscriminator, node->getKind());
1317+
if (auto *dc = findDeclContext(child))
1318+
if (auto typeDecl = findTypeDecl(dc, Ctx.getIdentifier(name),
1319+
privateDiscriminator, node->getKind()))
1320+
return typeDecl;
1321+
1322+
return nullptr;
13001323
}
13011324

13021325
case Demangle::Node::Kind::Global:
13031326
return findDeclContext(node->getChild(0));
13041327

13051328
case Demangle::Node::Kind::Extension: {
1306-
auto *moduleDecl = dyn_cast_or_null<ModuleDecl>(
1307-
findDeclContext(node->getChild(0)));
1308-
if (!moduleDecl)
1329+
auto moduleDecls = findPotentialModules(node->getFirstChild());
1330+
if (moduleDecls.empty())
13091331
return nullptr;
13101332

13111333
auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>(
@@ -1327,14 +1349,23 @@ ASTBuilder::findDeclContext(NodePointer node) {
13271349
// If the generic signature is equivalent to that of the nominal type,
13281350
// and we're in the same module, it's due to inverse requirements.
13291351
// Just return the nominal declaration.
1330-
if (genericSigMatchesNominal &&
1331-
nominalDecl->getParentModule() == moduleDecl) {
1332-
return nominalDecl;
1352+
for (auto *moduleDecl : moduleDecls) {
1353+
if (genericSigMatchesNominal &&
1354+
nominalDecl->getParentModule() == moduleDecl) {
1355+
return nominalDecl;;
1356+
}
13331357
}
13341358
}
13351359

13361360
for (auto *ext : nominalDecl->getExtensions()) {
1337-
if (ext->getParentModule() != moduleDecl)
1361+
bool found = false;
1362+
for (ModuleDecl *module : moduleDecls) {
1363+
if (ext->getParentModule() == module) {
1364+
found = true;
1365+
break;
1366+
}
1367+
}
1368+
if (!found)
13381369
continue;
13391370

13401371
if (!ext->isConstrainedExtension()) {

lib/AST/Module.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,11 @@ Identifier ModuleDecl::getABIName() const {
19561956
return getName();
19571957
}
19581958

1959+
void ModuleDecl::setABIName(Identifier name) {
1960+
getASTContext().moduleABINameWillChange(this, name);
1961+
ModuleABIName = name;
1962+
}
1963+
19591964
StringRef ModuleDecl::getModuleFilename() const {
19601965
// FIXME: Audit uses of this function and figure out how to migrate them to
19611966
// per-file names. Modules can consist of more than one file.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Tests that reconstructing from mangled names whose types are defined in modules
2+
// with clashing ABI names works.
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: split-file %s %t
6+
// RUN: cd %t
7+
8+
// RUN: %target-build-swift -emit-library -emit-module -parse-as-library -module-name Foo -module-abi-name Bar -g %t/Foo.swift
9+
// RUN: %target-build-swift -emit-executable -I %t -L %t -lFoo -g -emit-module -module-name Bar -module-abi-name Bar %t/Bar.swift
10+
11+
12+
// RUN: sed -ne '/\/\/ *DEMANGLE-TYPE: /s/\/\/ *DEMANGLE-TYPE: *//p' < %s > %t/input
13+
// RUN: %lldb-moduleimport-test-with-sdk %t/Bar -qualify-types=1 -type-from-mangled=%t/input | %FileCheck %s --check-prefix=CHECK-TYPE
14+
15+
//--- Foo.swift
16+
public class One {
17+
let i = 42
18+
public init() {
19+
}
20+
}
21+
22+
public class Generic<T> {
23+
let t: T
24+
public init(t: T) {
25+
self.t = t
26+
}
27+
}
28+
29+
//--- Bar.swift
30+
import Foo
31+
32+
public class Two {
33+
let j = 98
34+
public init() {
35+
}
36+
}
37+
38+
public class Generic2<T> {
39+
let t: T
40+
public init(t: T) {
41+
self.t = t
42+
}
43+
}
44+
45+
46+
let one = Foo.One()
47+
let two = Bar.Two()
48+
let generic1 = Foo.Generic<Bar.Two>(t: two)
49+
let generic2 = Bar.Generic2<Foo.Generic<Bar.Two>>(t: generic1)
50+
let generic3 = Foo.Generic<Bar.Generic2<Foo.Generic<Bar.Two>>>(t: generic2)
51+
52+
// DEMANGLE-TYPE: $s3Bar3OneCD
53+
// CHECK-TYPE: Foo.One
54+
55+
// DEMANGLE-TYPE: $s3Bar3TwoCD
56+
// CHECK-TYPE: Bar.Two
57+
58+
// DEMANGLE-TYPE: $s3Bar7GenericCyAA3TwoCGD
59+
// CHECK-TYPE: Foo.Generic<Bar.Two>
60+
61+
// DEMANGLE-TYPE: $s3Bar8Generic2CyAA7GenericCyAA3TwoCGGD
62+
// CHECK-TYPE: Bar.Generic2<Foo.Generic<Bar.Two>>
63+
64+
// DEMANGLE-TYPE: $s3Bar7GenericCyAA8Generic2CyACyAA3TwoCGGGD
65+
// CHECK-TYPE: Foo.Generic<Bar.Generic2<Foo.Generic<Bar.Two>>>

0 commit comments

Comments
 (0)