Skip to content

Commit 6956089

Browse files
committed
[CodeCompletion] Complete Swift only module name after 'import'
rdar://problem/39392446
1 parent c7052b0 commit 6956089

File tree

14 files changed

+237
-26
lines changed

14 files changed

+237
-26
lines changed

include/swift/AST/ASTContext.h

+4
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,10 @@ class ASTContext final {
860860
/// not necessarily loaded.
861861
void getVisibleTopLevelClangModules(SmallVectorImpl<clang::Module*> &Modules) const;
862862

863+
/// Populate \p names with visible top level module names.
864+
/// This guarantees that resulted \p names doesn't have duplicated names.
865+
void getVisibleTopLevelModuleNames(SmallVectorImpl<Identifier> &names) const;
866+
863867
private:
864868
/// Register the given generic signature builder to be used as the canonical
865869
/// generic signature builder for the given signature, if we don't already

include/swift/AST/ModuleLoader.h

+7
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ class ModuleLoader {
8282
public:
8383
virtual ~ModuleLoader() = default;
8484

85+
/// Collect visible module names.
86+
///
87+
/// Append visible module names to \p names. Note that names are possibly
88+
/// duplicated, and not guaranteed to be ordered in any way.
89+
virtual void collectVisibleTopLevelModuleNames(
90+
SmallVectorImpl<Identifier> &names) const = 0;
91+
8592
/// Check whether the module with a given name can be imported without
8693
/// importing it.
8794
///

include/swift/ClangImporter/ClangImporter.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ class ClangImporter final : public ClangModuleLoader {
119119
static std::shared_ptr<clang::DependencyCollector>
120120
createDependencyCollector(bool TrackSystemDeps);
121121

122+
/// Append visible module names to \p names. Note that names are possibly
123+
/// duplicated, and not guaranteed to be ordered in any way.
124+
void collectVisibleTopLevelModuleNames(
125+
SmallVectorImpl<Identifier> &names) const override;
126+
122127
/// Check whether the module with a given name can be imported without
123128
/// importing it.
124129
///
@@ -336,7 +341,7 @@ class ClangImporter final : public ClangModuleLoader {
336341
/// Calling this function does not load the module.
337342
void collectSubModuleNames(
338343
ArrayRef<std::pair<Identifier, SourceLoc>> path,
339-
std::vector<std::string> &names);
344+
std::vector<std::string> &names) const;
340345

341346
/// Given a Clang module, decide whether this module is imported already.
342347
static bool isModuleImported(const clang::Module *M);

include/swift/DWARFImporter/DWARFImporter.h

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class DWARFImporter final : public ClangModuleLoader {
6666

6767
~DWARFImporter();
6868

69+
void collectVisibleTopLevelModuleNames(
70+
SmallVectorImpl<Identifier> &names) const override;
71+
6972
/// Check whether the module with a given name can be imported without
7073
/// importing it.
7174
///

include/swift/Frontend/ParseableInterfaceModuleLoader.h

+5
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ class ParseableInterfaceModuleLoader : public SerializedModuleLoaderBase {
154154
RemarkOnRebuildFromInterface));
155155
}
156156

157+
/// Append visible module names to \p names. Note that names are possibly
158+
/// duplicated, and not guaranteed to be ordered in any way.
159+
void collectVisibleTopLevelModuleNames(
160+
SmallVectorImpl<Identifier> &names) const override;
161+
157162
/// Unconditionally build \p InPath (a swiftinterface file) to \p OutPath (as
158163
/// a swiftmodule file).
159164
///

include/swift/Sema/SourceLoader.h

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class SourceLoader : public ModuleLoader {
4848
SourceLoader &operator=(const SourceLoader &) = delete;
4949
SourceLoader &operator=(SourceLoader &&) = delete;
5050

51+
/// Append visible module names to \p names. Note that names are possibly
52+
/// duplicated, and not guaranteed to be ordered in any way.
53+
void collectVisibleTopLevelModuleNames(
54+
SmallVectorImpl<Identifier> &names) const override;
55+
5156
/// Check whether the module with a given name can be imported without
5257
/// importing it.
5358
///

include/swift/Serialization/SerializedModuleLoader.h

+11
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class SerializedModuleLoaderBase : public ModuleLoader {
4444
SerializedModuleLoaderBase(ASTContext &ctx, DependencyTracker *tracker,
4545
ModuleLoadingMode LoadMode);
4646

47+
void collectVisibleTopLevelModuleNamesImpl(SmallVectorImpl<Identifier> &names,
48+
StringRef extension) const;
49+
4750
using AccessPathElem = std::pair<Identifier, SourceLoc>;
4851
bool findModule(AccessPathElem moduleID,
4952
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
@@ -169,6 +172,11 @@ class SerializedModuleLoader : public SerializedModuleLoaderBase {
169172
public:
170173
virtual ~SerializedModuleLoader();
171174

175+
/// Append visible module names to \p names. Note that names are possibly
176+
/// duplicated, and not guaranteed to be ordered in any way.
177+
void collectVisibleTopLevelModuleNames(
178+
SmallVectorImpl<Identifier> &names) const override;
179+
172180
/// Create a new importer that can load serialized Swift modules
173181
/// into the given ASTContext.
174182
static std::unique_ptr<SerializedModuleLoader>
@@ -220,6 +228,9 @@ class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase {
220228
MemoryBuffers[AccessPath] = std::move(input);
221229
}
222230

231+
void collectVisibleTopLevelModuleNames(
232+
SmallVectorImpl<Identifier> &names) const override {}
233+
223234
/// Create a new importer that can load serialized Swift modules
224235
/// into the given ASTContext.
225236
static std::unique_ptr<MemoryBufferSerializedModuleLoader>

lib/AST/ASTContext.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,19 @@ void ProtocolDecl::setDefaultAssociatedConformanceWitness(
16701670
(void)pair;
16711671
}
16721672

1673+
void ASTContext::getVisibleTopLevelModuleNames(
1674+
SmallVectorImpl<Identifier> &names) const {
1675+
names.clear();
1676+
for (auto &importer : getImpl().ModuleLoaders)
1677+
importer->collectVisibleTopLevelModuleNames(names);
1678+
1679+
// Sort and unique.
1680+
std::sort(names.begin(), names.end(), [](Identifier LHS, Identifier RHS) {
1681+
return LHS.str().compare_lower(RHS.str()) < 0;
1682+
});
1683+
names.erase(std::unique(names.begin(), names.end()), names.end());
1684+
}
1685+
16731686
bool ASTContext::canImportModule(std::pair<Identifier, SourceLoc> ModulePath) {
16741687
// If this module has already been successfully imported, it is importable.
16751688
if (getLoadedModule(ModulePath) != nullptr)

lib/ClangImporter/ClangImporter.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -1494,9 +1494,22 @@ ClangImporter::emitBridgingPCH(StringRef headerPath,
14941494
return false;
14951495
}
14961496

1497+
void ClangImporter::collectVisibleTopLevelModuleNames(
1498+
SmallVectorImpl<Identifier> &names) const {
1499+
SmallVector<clang::Module *, 32> Modules;
1500+
Impl.getClangPreprocessor().getHeaderSearchInfo().collectAllModules(Modules);
1501+
for (auto &M : Modules) {
1502+
if (!M->isAvailable())
1503+
continue;
1504+
1505+
names.push_back(
1506+
Impl.SwiftContext.getIdentifier(M->getTopLevelModuleName()));
1507+
}
1508+
}
1509+
14971510
void ClangImporter::collectSubModuleNames(
14981511
ArrayRef<std::pair<Identifier, SourceLoc>> path,
1499-
std::vector<std::string> &names) {
1512+
std::vector<std::string> &names) const {
15001513
auto &clangHeaderSearch = Impl.getClangPreprocessor().getHeaderSearchInfo();
15011514

15021515
// Look up the top-level module first.

lib/DWARFImporter/DWARFImporter.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ DWARFImporter::DWARFImporter(ASTContext &ctx,
142142

143143
DWARFImporter::~DWARFImporter() { delete &Impl; }
144144

145+
void DWARFImporter::collectVisibleTopLevelModuleNames(
146+
SmallVectorImpl<Identifier> &names) const {}
147+
145148
bool DWARFImporter::canImportModule(std::pair<Identifier, SourceLoc> named) {
146149
return false;
147150
}

lib/Frontend/ParseableInterfaceModuleLoader.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1377,3 +1377,10 @@ bool ParseableInterfaceModuleLoader::buildSwiftModuleFromSwiftInterface(
13771377
return builder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true,
13781378
/*ModuleBuffer*/nullptr);
13791379
}
1380+
1381+
void ParseableInterfaceModuleLoader::collectVisibleTopLevelModuleNames(
1382+
SmallVectorImpl<Identifier> &names) const {
1383+
collectVisibleTopLevelModuleNamesImpl(
1384+
names,
1385+
file_types::getExtension(file_types::TY_SwiftParseableInterfaceFile));
1386+
}

lib/IDE/CodeCompletion.cpp

+11-24
Original file line numberDiff line numberDiff line change
@@ -1753,35 +1753,22 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
17531753
}
17541754

17551755
void addImportModuleNames() {
1756-
// FIXME: Add user-defined swift modules
1757-
SmallVector<StringRef, 20> ModuleNames;
1758-
1759-
// Collect clang module names.
1760-
{
1761-
SmallVector<clang::Module*, 20> ClangModules;
1762-
Ctx.getVisibleTopLevelClangModules(ClangModules);
1763-
for (auto *M : ClangModules) {
1764-
if (!M->isAvailable())
1765-
continue;
1766-
if (M->getTopLevelModuleName().startswith("_"))
1767-
continue;
1768-
if (M->getTopLevelModuleName() == Ctx.SwiftShimsModuleName.str())
1769-
continue;
1770-
1771-
ModuleNames.push_back(M->getTopLevelModuleName());
1772-
}
1773-
}
1774-
1775-
std::sort(ModuleNames.begin(), ModuleNames.end(),
1776-
[](StringRef LHS, StringRef RHS) {
1777-
return LHS.compare_lower(RHS) < 0;
1778-
});
1756+
SmallVector<Identifier, 0> ModuleNames;
1757+
Ctx.getVisibleTopLevelModuleNames(ModuleNames);
17791758

17801759
llvm::StringSet<> ImportedModules;
17811760
collectImportedModules(ImportedModules);
17821761

1762+
auto mainModuleName = CurrDeclContext->getParentModule()->getName();
17831763
for (auto ModuleName : ModuleNames) {
1784-
auto MD = ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx);
1764+
if (ModuleName == mainModuleName)
1765+
continue;
1766+
if (ModuleName.str().startswith("_"))
1767+
continue;
1768+
if (ModuleName == Ctx.SwiftShimsModuleName)
1769+
continue;
1770+
1771+
auto MD = ModuleDecl::create(ModuleName, Ctx);
17851772
CodeCompletionResultBuilder Builder(
17861773
Sink,
17871774
CodeCompletionResult::ResultKind::Declaration,

lib/Sema/SourceLoader.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ class SkipNonTransparentFunctions : public DelayedParsingCallbacks {
7070

7171
} // unnamed namespace
7272

73+
void SourceLoader::collectVisibleTopLevelModuleNames(
74+
SmallVectorImpl<Identifier> &names) const {
75+
// TODO: Implement?
76+
}
77+
7378
bool SourceLoader::canImportModule(std::pair<Identifier, SourceLoc> ID) {
7479
// Search the memory buffers to see if we can find this file on disk.
7580
FileOrError inputFileOrError = findModule(Ctx, ID.first.str(),

lib/Serialization/SerializedModuleLoader.cpp

+143
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,149 @@ SerializedModuleLoader::~SerializedModuleLoader() = default;
4444
MemoryBufferSerializedModuleLoader::~MemoryBufferSerializedModuleLoader() =
4545
default;
4646

47+
void SerializedModuleLoaderBase::collectVisibleTopLevelModuleNamesImpl(
48+
SmallVectorImpl<Identifier> &names, StringRef extension) const {
49+
llvm::SmallString<16> moduleSuffix;
50+
moduleSuffix += '.';
51+
moduleSuffix += file_types::getExtension(file_types::TY_SwiftModuleFile);
52+
53+
llvm::SmallString<16> suffix;
54+
suffix += '.';
55+
suffix += extension;
56+
57+
SmallVector<SmallString<64>, 3> targetFiles;
58+
targetFiles.emplace_back(
59+
getTargetSpecificModuleTriple(Ctx.LangOpts.Target).str());
60+
targetFiles.back() += suffix;
61+
targetFiles.emplace_back(Ctx.LangOpts.Target.getArchName());
62+
targetFiles.back() += suffix;
63+
64+
auto &fs = *Ctx.SourceMgr.getFileSystem();
65+
66+
// Apply \p body for each directory entry in \p dirPath.
67+
auto forEachDirectoryEntryPath =
68+
[&](StringRef dirPath, llvm::function_ref<void(StringRef)> body) {
69+
std::error_code errorCode;
70+
llvm::vfs::directory_iterator DI = fs.dir_begin(dirPath, errorCode);
71+
llvm::vfs::directory_iterator End;
72+
for (; !errorCode && DI != End; DI.increment(errorCode))
73+
body(DI->path());
74+
};
75+
76+
// Check whether target specific module file exists or not in given directory.
77+
// $PATH/{arch}.{extension}
78+
auto checkTargetFiles = [&](StringRef path) -> bool {
79+
llvm::SmallString<256> scratch;
80+
for (auto targetFile : targetFiles) {
81+
scratch.clear();
82+
llvm::sys::path::append(scratch, path, targetFile);
83+
// If {arch}.{extension} exists, consider it's visible. Technically, we
84+
// should check the file type, permission, format, etc., but it's too
85+
// heavy to do that for each files.
86+
if (fs.exists(scratch))
87+
return true;
88+
}
89+
return false;
90+
};
91+
92+
auto tryImportSearchPath = [&](StringRef searchPath) {
93+
// Look for:
94+
// $PATH/{name}.swiftmodule/{arch}.{extension} ; Or
95+
// $PATH/{name}.{extension}
96+
forEachDirectoryEntryPath(searchPath, [&](StringRef path) {
97+
auto pathExt = llvm::sys::path::extension(path);
98+
if (pathExt != moduleSuffix && pathExt != suffix)
99+
return;
100+
101+
auto stat = fs.status(path);
102+
if (!stat)
103+
return;
104+
if (pathExt == moduleSuffix && stat->isDirectory()) {
105+
if (!checkTargetFiles(path))
106+
return;
107+
} else if (pathExt != suffix) {
108+
return;
109+
}
110+
// Extract module name.
111+
auto name = llvm::sys::path::filename(path).drop_back(pathExt.size());
112+
names.push_back(Ctx.getIdentifier(name));
113+
});
114+
};
115+
116+
auto tryRuntimeLibraryPath = [&](StringRef searchPath) {
117+
// Look for:
118+
// (Darwin OS) $PATH/{name}.swiftmodule/{arch}.{extension}
119+
// (Other OS) $PATH/{name}.{extension}
120+
bool requireTargetSpecificModule = Ctx.LangOpts.Target.isOSDarwin();
121+
forEachDirectoryEntryPath(searchPath, [&](StringRef path) {
122+
auto pathExt = llvm::sys::path::extension(path);
123+
if (requireTargetSpecificModule) {
124+
if (pathExt != moduleSuffix)
125+
return;
126+
if (!checkTargetFiles(path))
127+
return;
128+
} else {
129+
auto stat = fs.status(path);
130+
if (!stat || stat->isDirectory())
131+
return;
132+
if (suffix != pathExt)
133+
return;
134+
}
135+
// Extract module name.
136+
auto name = llvm::sys::path::filename(path).drop_back(pathExt.size());
137+
names.push_back(Ctx.getIdentifier(name));
138+
});
139+
};
140+
141+
auto tryFrameworkSearchPath = [&](StringRef searchPath) {
142+
// Look for:
143+
// $PATH/{name}.framework/Modules/{name}.swiftmodule/{arch}.{extension}
144+
forEachDirectoryEntryPath(searchPath, [&](StringRef path) {
145+
if (llvm::sys::path::extension(path) != ".framework")
146+
return;
147+
148+
// Extract Framework name.
149+
auto name = llvm::sys::path::filename(path).drop_back(
150+
StringLiteral(".framework").size());
151+
152+
SmallString<128> moduleDir;
153+
llvm::sys::path::append(moduleDir, path, "Modules", name + moduleSuffix);
154+
if (!checkTargetFiles(moduleDir))
155+
return;
156+
157+
names.push_back(Ctx.getIdentifier(name));
158+
});
159+
};
160+
161+
for (const auto &path : Ctx.SearchPathOpts.ImportSearchPaths)
162+
tryImportSearchPath(path);
163+
164+
for (const auto &path : Ctx.SearchPathOpts.FrameworkSearchPaths)
165+
tryFrameworkSearchPath(path.Path);
166+
167+
// Apple platforms have extra implicit framework search paths:
168+
// $SDKROOT/System/Library/Frameworks/ and $SDKROOT/Library/Frameworks/
169+
if (Ctx.LangOpts.Target.isOSDarwin()) {
170+
SmallString<128> scratch;
171+
scratch = Ctx.SearchPathOpts.SDKPath;
172+
llvm::sys::path::append(scratch, "System", "Library", "Frameworks");
173+
tryFrameworkSearchPath(scratch);
174+
175+
scratch = Ctx.SearchPathOpts.SDKPath;
176+
llvm::sys::path::append(scratch, "Library", "Frameworks");
177+
tryFrameworkSearchPath(scratch);
178+
}
179+
180+
for (auto importPath : Ctx.SearchPathOpts.RuntimeLibraryImportPaths)
181+
tryRuntimeLibraryPath(importPath);
182+
}
183+
184+
void SerializedModuleLoader::collectVisibleTopLevelModuleNames(
185+
SmallVectorImpl<Identifier> &names) const {
186+
collectVisibleTopLevelModuleNamesImpl(
187+
names, file_types::getExtension(file_types::TY_SwiftModuleFile));
188+
}
189+
47190
std::error_code SerializedModuleLoaderBase::openModuleDocFile(
48191
AccessPathElem ModuleID, StringRef ModuleDocPath,
49192
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) {

0 commit comments

Comments
 (0)