Skip to content

Commit b2538e9

Browse files
authored
Merge pull request #19186 from jrose-apple/full-reverse
When sorting imports for uniquing purposes, use full module names
2 parents b4a23ad + 3c5fba3 commit b2538e9

File tree

9 files changed

+147
-64
lines changed

9 files changed

+147
-64
lines changed

include/swift/AST/Module.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,45 @@ class ModuleDecl : public DeclContext, public TypeDecl {
151151
}
152152
};
153153

154+
/// Produces the components of a given module's full name in reverse order.
155+
///
156+
/// For a Swift module, this will only ever have one component, but an
157+
/// imported Clang module might actually be a submodule.
158+
class ReverseFullNameIterator {
159+
public:
160+
// Make this look like a valid STL iterator.
161+
using difference_type = int;
162+
using value_type = StringRef;
163+
using pointer = StringRef *;
164+
using reference = StringRef;
165+
using iterator_category = std::forward_iterator_tag;
166+
167+
private:
168+
PointerUnion<const ModuleDecl *, const /* clang::Module */ void *> current;
169+
public:
170+
ReverseFullNameIterator() = default;
171+
explicit ReverseFullNameIterator(const ModuleDecl *M);
172+
explicit ReverseFullNameIterator(const clang::Module *clangModule) {
173+
current = clangModule;
174+
}
175+
176+
StringRef operator*() const;
177+
ReverseFullNameIterator &operator++();
178+
179+
friend bool operator==(ReverseFullNameIterator left,
180+
ReverseFullNameIterator right) {
181+
return left.current == right.current;
182+
}
183+
friend bool operator!=(ReverseFullNameIterator left,
184+
ReverseFullNameIterator right) {
185+
return !(left == right);
186+
}
187+
188+
/// This is a convenience function that writes the entire name, in forward
189+
/// order, to \p out.
190+
void printForward(raw_ostream &out) const;
191+
};
192+
154193
private:
155194
/// If non-NULL, a plug-in that should be used when performing external
156195
/// lookups.
@@ -490,6 +529,15 @@ class ModuleDecl : public DeclContext, public TypeDecl {
490529
/// Returns the associated clang module if one exists.
491530
const clang::Module *findUnderlyingClangModule() const;
492531

532+
/// Returns a generator with the components of this module's full,
533+
/// hierarchical name.
534+
///
535+
/// For a Swift module, this will only ever have one component, but an
536+
/// imported Clang module might actually be a submodule.
537+
ReverseFullNameIterator getReverseFullModuleName() const {
538+
return ReverseFullNameIterator(this);
539+
}
540+
493541
SourceRange getSourceRange() const { return SourceRange(); }
494542

495543
static bool classof(const DeclContext *DC) {

lib/AST/Module.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,14 +1005,65 @@ bool ModuleDecl::isSameAccessPath(AccessPathTy lhs, AccessPathTy rhs) {
10051005
});
10061006
}
10071007

1008+
ModuleDecl::ReverseFullNameIterator::ReverseFullNameIterator(
1009+
const ModuleDecl *M) {
1010+
assert(M);
1011+
// Note: This will look through overlays as well, but that's fine for name
1012+
// generation purposes. The point of an overlay is to
1013+
if (auto *clangModule = M->findUnderlyingClangModule())
1014+
current = clangModule;
1015+
else
1016+
current = M;
1017+
}
1018+
1019+
StringRef ModuleDecl::ReverseFullNameIterator::operator*() const {
1020+
assert(current && "all name components exhausted");
1021+
1022+
if (auto *swiftModule = current.dyn_cast<const ModuleDecl *>())
1023+
return swiftModule->getName().str();
1024+
1025+
auto *clangModule =
1026+
static_cast<const clang::Module *>(current.get<const void *>());
1027+
return clangModule->Name;
1028+
}
1029+
1030+
ModuleDecl::ReverseFullNameIterator &
1031+
ModuleDecl::ReverseFullNameIterator::operator++() {
1032+
if (!current)
1033+
return *this;
1034+
1035+
if (auto *swiftModule = current.dyn_cast<const ModuleDecl *>()) {
1036+
current = nullptr;
1037+
return *this;
1038+
}
1039+
1040+
auto *clangModule =
1041+
static_cast<const clang::Module *>(current.get<const void *>());
1042+
if (clangModule->Parent)
1043+
current = clangModule->Parent;
1044+
else
1045+
current = nullptr;
1046+
return *this;
1047+
}
1048+
1049+
void
1050+
ModuleDecl::ReverseFullNameIterator::printForward(raw_ostream &out) const {
1051+
SmallVector<StringRef, 8> elements(*this, {});
1052+
swift::interleave(swift::reversed(elements),
1053+
[&out](StringRef next) { out << next; },
1054+
[&out] { out << '.'; });
1055+
}
1056+
10081057
void
10091058
ModuleDecl::removeDuplicateImports(SmallVectorImpl<ImportedModule> &imports) {
10101059
std::sort(imports.begin(), imports.end(),
10111060
[](const ImportedModule &lhs, const ImportedModule &rhs) -> bool {
10121061
// Arbitrarily sort by name to get a deterministic order.
1013-
// FIXME: Submodules don't get sorted properly here.
1014-
if (lhs.second != rhs.second)
1015-
return lhs.second->getName().str() < rhs.second->getName().str();
1062+
if (lhs.second != rhs.second) {
1063+
return std::lexicographical_compare(
1064+
lhs.second->getReverseFullModuleName(), {},
1065+
rhs.second->getReverseFullModuleName(), {});
1066+
}
10161067
using AccessPathElem = std::pair<Identifier, SourceLoc>;
10171068
return std::lexicographical_compare(lhs.first.begin(), lhs.first.end(),
10181069
rhs.first.begin(), rhs.first.end(),

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,12 +1451,8 @@ void ClangImporter::collectSubModuleNames(
14511451
if (!submodule)
14521452
return;
14531453
}
1454-
auto submoduleNameLength = submodule->getFullModuleName().length();
1455-
for (auto sub : submodule->submodules()) {
1456-
std::string full = sub->getFullModuleName();
1457-
full.erase(0, submoduleNameLength + 1);
1458-
names.push_back(std::move(full));
1459-
}
1454+
for (auto sub : submodule->submodules())
1455+
names.push_back(sub->Name);
14601456
}
14611457

14621458
bool ClangImporter::isModuleImported(const clang::Module *M) {

lib/FrontendTool/TextualInterfaceGeneration.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ static void printImports(raw_ostream &out, ModuleDecl *M) {
6464
if (publicImportSet.count(import))
6565
out << "@_exported ";
6666
out << "import ";
67-
if (auto *clangModule = import.second->findUnderlyingClangModule())
68-
out << clangModule->getFullModuleName();
69-
else
70-
out << import.second->getName();
67+
import.second->getReverseFullModuleName().printForward(out);
7168

7269
// Write the access path we should be honoring but aren't.
7370
// (See diagnoseScopedImports above.)

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2654,15 +2654,6 @@ class ModuleWriter {
26542654
return import == importer->getImportedHeaderModule();
26552655
}
26562656

2657-
static void getClangSubmoduleReversePath(SmallVectorImpl<StringRef> &path,
2658-
const clang::Module *module) {
2659-
// FIXME: This should be an API on clang::Module.
2660-
do {
2661-
path.push_back(module->Name);
2662-
module = module->Parent;
2663-
} while (module);
2664-
}
2665-
26662657
static int compareImportModulesByName(const ImportModuleTy *left,
26672658
const ImportModuleTy *right) {
26682659
auto *leftSwiftModule = left->dyn_cast<ModuleDecl *>();
@@ -2692,10 +2683,10 @@ class ModuleWriter {
26922683
assert(rightClangModule->isSubModule() &&
26932684
"top-level modules should use a normal swift::ModuleDecl");
26942685

2695-
SmallVector<StringRef, 8> leftReversePath;
2696-
SmallVector<StringRef, 8> rightReversePath;
2697-
getClangSubmoduleReversePath(leftReversePath, leftClangModule);
2698-
getClangSubmoduleReversePath(rightReversePath, rightClangModule);
2686+
SmallVector<StringRef, 8> leftReversePath(
2687+
ModuleDecl::ReverseFullNameIterator(leftClangModule), {});
2688+
SmallVector<StringRef, 8> rightReversePath(
2689+
ModuleDecl::ReverseFullNameIterator(rightClangModule), {});
26992690

27002691
assert(leftReversePath != rightReversePath &&
27012692
"distinct Clang modules should not have the same full name");
@@ -2734,11 +2725,7 @@ class ModuleWriter {
27342725
assert(clangModule->isSubModule() &&
27352726
"top-level modules should use a normal swift::ModuleDecl");
27362727
out << "@import ";
2737-
SmallVector<StringRef, 8> submoduleNames;
2738-
getClangSubmoduleReversePath(submoduleNames, clangModule);
2739-
interleave(submoduleNames.rbegin(), submoduleNames.rend(),
2740-
[&out](StringRef next) { out << next; },
2741-
[&out] { out << "."; });
2728+
ModuleDecl::ReverseFullNameIterator(clangModule).printForward(out);
27422729
out << ";\n";
27432730
}
27442731
}

lib/Serialization/Serialization.cpp

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@
3737
#include "swift/ClangImporter/ClangModule.h"
3838
#include "swift/Serialization/SerializationOptions.h"
3939
#include "swift/Strings.h"
40-
41-
#include "clang/Basic/Module.h"
42-
4340
#include "llvm/ADT/SmallString.h"
4441
#include "llvm/ADT/StringExtras.h"
4542
#include "llvm/Bitcode/BitstreamWriter.h"
@@ -1032,22 +1029,12 @@ void Serializer::writeDocHeader() {
10321029
using ImportPathBlob = llvm::SmallString<64>;
10331030
static void flattenImportPath(const ModuleDecl::ImportedModule &import,
10341031
ImportPathBlob &out) {
1035-
ArrayRef<FileUnit *> files = import.second->getFiles();
1036-
if (auto clangModule = dyn_cast<ClangModuleUnit>(files.front())) {
1037-
// FIXME: This is an awful hack to handle Clang submodules.
1038-
// Once Swift has a native notion of submodules, this can go away.
1039-
const clang::Module *submodule = clangModule->getClangModule();
1040-
SmallVector<StringRef, 4> submoduleNames;
1041-
do {
1042-
submoduleNames.push_back(submodule->Name);
1043-
submodule = submodule->Parent;
1044-
} while (submodule);
1045-
interleave(submoduleNames.rbegin(), submoduleNames.rend(),
1046-
[&out](StringRef next) { out.append(next); },
1047-
[&out] { out.push_back('\0'); });
1048-
} else {
1049-
out.append(import.second->getName().str());
1050-
}
1032+
SmallVector<StringRef, 4> reverseSubmoduleNames(
1033+
import.second->getReverseFullModuleName(), {});
1034+
1035+
interleave(reverseSubmoduleNames.rbegin(), reverseSubmoduleNames.rend(),
1036+
[&out](StringRef next) { out.append(next); },
1037+
[&out] { out.push_back('\0'); });
10511038

10521039
if (import.first.empty())
10531040
return;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module X {
2+
explicit module Submodule {}
3+
}
4+
5+
module Y {
6+
explicit module Submodule {}
7+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ | %FileCheck %s
2+
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s -I %S/Inputs/imports-submodule-order/ -D XY | %FileCheck %s
3+
4+
#if XY
5+
@_exported import X.Submodule
6+
@_exported import Y.Submodule
7+
8+
#else
9+
@_exported import Y.Submodule
10+
@_exported import X.Submodule
11+
12+
#endif
13+
14+
// The order below is not alphabetical, just deterministic given a set of
15+
// imports across any number of files and in any order.
16+
17+
// CHECK-NOT: import
18+
// CHECK: import X.Submodule{{$}}
19+
// CHECK-NEXT: import Y.Submodule{{$}}
20+
// CHECK-NEXT: import X{{$}}
21+
// CHECK-NEXT: import Y{{$}}
22+
// CHECK-NOT: import

tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -416,21 +416,9 @@ static bool initDocEntityInfo(const Decl *D,
416416
case DeclContextKind::FileUnit: {
417417
if (auto *CD = D->getClangDecl()) {
418418
if (auto *M = CD->getImportedOwningModule()) {
419-
const clang::Module *Root = M->getTopLevelModule();
420-
421-
// If Root differs from the owning module, then the owning module is
422-
// a sub-module.
423-
if (M != Root) {
419+
if (M->isSubModule()) {
424420
llvm::raw_svector_ostream OS(Info.SubModuleName);
425-
llvm::SmallVector<StringRef, 4> Names;
426-
427-
// Climb up and collect sub-module names.
428-
for (auto Current = M; Current != Root; Current = Current->Parent) {
429-
Names.insert(Names.begin(), Current->Name);
430-
}
431-
OS << Root->Name;
432-
std::for_each(Names.begin(), Names.end(),
433-
[&](StringRef N) { OS << "." << N; });
421+
ModuleDecl::ReverseFullNameIterator(M).printForward(OS);
434422
}
435423
}
436424
}

0 commit comments

Comments
 (0)