mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #32147 from hamishknight/modulo-module
This commit is contained in:
@@ -2494,6 +2494,25 @@ public:
|
|||||||
bool isCached() const { return true; }
|
bool isCached() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Retrieve the file being used for code completion in the main module.
|
||||||
|
// FIXME: This isn't really a type-checking request, if we ever split off a
|
||||||
|
// zone for more basic AST requests, this should be moved there.
|
||||||
|
class CodeCompletionFileRequest
|
||||||
|
: public SimpleRequest<CodeCompletionFileRequest,
|
||||||
|
SourceFile *(ModuleDecl *), RequestFlags::Cached> {
|
||||||
|
public:
|
||||||
|
using SimpleRequest::SimpleRequest;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend SimpleRequest;
|
||||||
|
|
||||||
|
SourceFile *evaluate(Evaluator &evaluator, ModuleDecl *mod) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Cached.
|
||||||
|
bool isCached() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
// Allow AnyValue to compare two Type values, even though Type doesn't
|
// Allow AnyValue to compare two Type values, even though Type doesn't
|
||||||
// support ==.
|
// support ==.
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ SWIFT_REQUEST(TypeChecker, CheckRedeclarationRequest,
|
|||||||
Uncached, NoLocationInfo)
|
Uncached, NoLocationInfo)
|
||||||
SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest,
|
SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest,
|
||||||
AncestryFlags(ClassDecl *), Cached, NoLocationInfo)
|
AncestryFlags(ClassDecl *), Cached, NoLocationInfo)
|
||||||
|
SWIFT_REQUEST(TypeChecker, CodeCompletionFileRequest,
|
||||||
|
SourceFile *(ModuleDecl *), Cached, NoLocationInfo)
|
||||||
SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest,
|
SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest,
|
||||||
bool (DeclContext *, ValueDecl *, ValueDecl *, bool), Cached,
|
bool (DeclContext *, ValueDecl *, ValueDecl *, bool), Cached,
|
||||||
NoLocationInfo)
|
NoLocationInfo)
|
||||||
|
|||||||
@@ -451,9 +451,6 @@ class CompilerInstance {
|
|||||||
/// considered primaries.
|
/// considered primaries.
|
||||||
llvm::SetVector<unsigned> PrimaryBufferIDs;
|
llvm::SetVector<unsigned> PrimaryBufferIDs;
|
||||||
|
|
||||||
/// The file that has been registered for code completion.
|
|
||||||
NullablePtr<SourceFile> CodeCompletionFile;
|
|
||||||
|
|
||||||
/// Return whether there is an entry in PrimaryInputs for buffer \p BufID.
|
/// Return whether there is an entry in PrimaryInputs for buffer \p BufID.
|
||||||
bool isPrimaryInput(unsigned BufID) const {
|
bool isPrimaryInput(unsigned BufID) const {
|
||||||
return PrimaryBufferIDs.count(BufID) != 0;
|
return PrimaryBufferIDs.count(BufID) != 0;
|
||||||
@@ -509,8 +506,13 @@ public:
|
|||||||
|
|
||||||
UnifiedStatsReporter *getStatsReporter() const { return Stats.get(); }
|
UnifiedStatsReporter *getStatsReporter() const { return Stats.get(); }
|
||||||
|
|
||||||
|
/// Retrieve the main module containing the files being compiled.
|
||||||
ModuleDecl *getMainModule() const;
|
ModuleDecl *getMainModule() const;
|
||||||
|
|
||||||
|
/// Replace the current main module with a new one. This is used for top-level
|
||||||
|
/// cached code completion.
|
||||||
|
void setMainModule(ModuleDecl *newMod);
|
||||||
|
|
||||||
MemoryBufferSerializedModuleLoader *
|
MemoryBufferSerializedModuleLoader *
|
||||||
getMemoryBufferSerializedModuleLoader() const {
|
getMemoryBufferSerializedModuleLoader() const {
|
||||||
return MemoryBufferLoader;
|
return MemoryBufferLoader;
|
||||||
@@ -557,12 +559,7 @@ public:
|
|||||||
|
|
||||||
/// If a code completion buffer has been set, returns the corresponding source
|
/// If a code completion buffer has been set, returns the corresponding source
|
||||||
/// file.
|
/// file.
|
||||||
NullablePtr<SourceFile> getCodeCompletionFile() { return CodeCompletionFile; }
|
SourceFile *getCodeCompletionFile() const;
|
||||||
|
|
||||||
/// Set a new file that we're performing code completion on.
|
|
||||||
void setCodeCompletionFile(SourceFile *file) {
|
|
||||||
CodeCompletionFile = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Set up the file system by loading and validating all VFS overlay YAML
|
/// Set up the file system by loading and validating all VFS overlay YAML
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class CompletionInstance {
|
|||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
|
|
||||||
std::unique_ptr<CompilerInstance> CachedCI;
|
std::unique_ptr<CompilerInstance> CachedCI;
|
||||||
ModuleDecl *CurrentModule = nullptr;
|
|
||||||
llvm::hash_code CachedArgHash;
|
llvm::hash_code CachedArgHash;
|
||||||
llvm::sys::TimePoint<> DependencyCheckedTimestamp;
|
llvm::sys::TimePoint<> DependencyCheckedTimestamp;
|
||||||
llvm::StringMap<llvm::hash_code> InMemoryDependencyHash;
|
llvm::StringMap<llvm::hash_code> InMemoryDependencyHash;
|
||||||
|
|||||||
@@ -532,6 +532,20 @@ ArrayRef<SourceFile *> ModuleDecl::getPrimarySourceFiles() const {
|
|||||||
return evaluateOrDefault(eval, PrimarySourceFilesRequest{mutableThis}, {});
|
return evaluateOrDefault(eval, PrimarySourceFilesRequest{mutableThis}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceFile *CodeCompletionFileRequest::evaluate(Evaluator &evaluator,
|
||||||
|
ModuleDecl *mod) const {
|
||||||
|
const auto &SM = mod->getASTContext().SourceMgr;
|
||||||
|
assert(mod->isMainModule() && "Can only do completion in the main module");
|
||||||
|
assert(SM.hasCodeCompletionBuffer() && "Not performing code completion?");
|
||||||
|
|
||||||
|
for (auto *file : mod->getFiles()) {
|
||||||
|
auto *SF = dyn_cast<SourceFile>(file);
|
||||||
|
if (SF && SF->getBufferID() == SM.getCodeCompletionBufferID())
|
||||||
|
return SF;
|
||||||
|
}
|
||||||
|
llvm_unreachable("Couldn't find the completion file?");
|
||||||
|
}
|
||||||
|
|
||||||
#define FORWARD(name, args) \
|
#define FORWARD(name, args) \
|
||||||
for (const FileUnit *file : getFiles()) \
|
for (const FileUnit *file : getFiles()) \
|
||||||
file->name args;
|
file->name args;
|
||||||
|
|||||||
@@ -489,6 +489,12 @@ Optional<unsigned> CompilerInstance::setUpCodeCompletionBuffer() {
|
|||||||
return codeCompletionBufferID;
|
return codeCompletionBufferID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceFile *CompilerInstance::getCodeCompletionFile() const {
|
||||||
|
auto *mod = getMainModule();
|
||||||
|
auto &eval = mod->getASTContext().evaluator;
|
||||||
|
return evaluateOrDefault(eval, CodeCompletionFileRequest{mod}, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
static bool shouldTreatSingleInputAsMain(InputFileKind inputKind) {
|
static bool shouldTreatSingleInputAsMain(InputFileKind inputKind) {
|
||||||
switch (inputKind) {
|
switch (inputKind) {
|
||||||
case InputFileKind::Swift:
|
case InputFileKind::Swift:
|
||||||
@@ -707,6 +713,12 @@ ModuleDecl *CompilerInstance::getMainModule() const {
|
|||||||
return MainModule;
|
return MainModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerInstance::setMainModule(ModuleDecl *newMod) {
|
||||||
|
assert(newMod->isMainModule());
|
||||||
|
MainModule = newMod;
|
||||||
|
Context->LoadedModules[newMod->getName()] = newMod;
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerInstance::performParseOnly(bool EvaluateConditionals,
|
void CompilerInstance::performParseOnly(bool EvaluateConditionals,
|
||||||
bool CanDelayBodies) {
|
bool CanDelayBodies) {
|
||||||
const InputFileKind Kind = Invocation.getInputKind();
|
const InputFileKind Kind = Invocation.getInputKind();
|
||||||
@@ -899,12 +911,6 @@ SourceFile *CompilerInstance::createSourceFileForMainModule(
|
|||||||
if (isPrimary) {
|
if (isPrimary) {
|
||||||
inputFile->enableInterfaceHash();
|
inputFile->enableInterfaceHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferID == SourceMgr.getCodeCompletionBufferID()) {
|
|
||||||
assert(!CodeCompletionFile && "Multiple code completion files?");
|
|
||||||
CodeCompletionFile = inputFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputFile;
|
return inputFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,11 +169,10 @@ static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC,
|
|||||||
/// returns \c true. Returns \c true if any callback call returns \c true, \c
|
/// returns \c true. Returns \c true if any callback call returns \c true, \c
|
||||||
/// false otherwise.
|
/// false otherwise.
|
||||||
static bool
|
static bool
|
||||||
forEachDependencyUntilTrue(CompilerInstance &CI, ModuleDecl *CurrentModule,
|
forEachDependencyUntilTrue(CompilerInstance &CI, unsigned excludeBufferID,
|
||||||
unsigned excludeBufferID,
|
|
||||||
llvm::function_ref<bool(StringRef)> callback) {
|
llvm::function_ref<bool(StringRef)> callback) {
|
||||||
// Check files in the current module.
|
// Check files in the current module.
|
||||||
for (FileUnit *file : CurrentModule->getFiles()) {
|
for (FileUnit *file : CI.getMainModule()->getFiles()) {
|
||||||
StringRef filename;
|
StringRef filename;
|
||||||
if (auto SF = dyn_cast<SourceFile>(file)) {
|
if (auto SF = dyn_cast<SourceFile>(file)) {
|
||||||
if (SF->getBufferID() == excludeBufferID)
|
if (SF->getBufferID() == excludeBufferID)
|
||||||
@@ -203,12 +202,11 @@ forEachDependencyUntilTrue(CompilerInstance &CI, ModuleDecl *CurrentModule,
|
|||||||
|
|
||||||
/// Collect hash codes of the dependencies into \c Map.
|
/// Collect hash codes of the dependencies into \c Map.
|
||||||
static void cacheDependencyHashIfNeeded(CompilerInstance &CI,
|
static void cacheDependencyHashIfNeeded(CompilerInstance &CI,
|
||||||
ModuleDecl *CurrentModule,
|
|
||||||
unsigned excludeBufferID,
|
unsigned excludeBufferID,
|
||||||
llvm::StringMap<llvm::hash_code> &Map) {
|
llvm::StringMap<llvm::hash_code> &Map) {
|
||||||
auto &FS = CI.getFileSystem();
|
auto &FS = CI.getFileSystem();
|
||||||
forEachDependencyUntilTrue(
|
forEachDependencyUntilTrue(
|
||||||
CI, CurrentModule, excludeBufferID, [&](StringRef filename) {
|
CI, excludeBufferID, [&](StringRef filename) {
|
||||||
if (Map.count(filename))
|
if (Map.count(filename))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -229,12 +227,12 @@ static void cacheDependencyHashIfNeeded(CompilerInstance &CI,
|
|||||||
|
|
||||||
/// Check if any dependent files are modified since \p timestamp.
|
/// Check if any dependent files are modified since \p timestamp.
|
||||||
static bool areAnyDependentFilesInvalidated(
|
static bool areAnyDependentFilesInvalidated(
|
||||||
CompilerInstance &CI, ModuleDecl *CurrentModule, llvm::vfs::FileSystem &FS,
|
CompilerInstance &CI, llvm::vfs::FileSystem &FS,
|
||||||
unsigned excludeBufferID, llvm::sys::TimePoint<> timestamp,
|
unsigned excludeBufferID, llvm::sys::TimePoint<> timestamp,
|
||||||
llvm::StringMap<llvm::hash_code> &Map) {
|
llvm::StringMap<llvm::hash_code> &Map) {
|
||||||
|
|
||||||
return forEachDependencyUntilTrue(
|
return forEachDependencyUntilTrue(
|
||||||
CI, CurrentModule, excludeBufferID, [&](StringRef filePath) {
|
CI, excludeBufferID, [&](StringRef filePath) {
|
||||||
auto stat = FS.status(filePath);
|
auto stat = FS.status(filePath);
|
||||||
if (!stat)
|
if (!stat)
|
||||||
// Missing.
|
// Missing.
|
||||||
@@ -291,7 +289,7 @@ bool CompletionInstance::performCachedOperationIfPossible(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto &CI = *CachedCI;
|
auto &CI = *CachedCI;
|
||||||
auto *oldSF = CI.getCodeCompletionFile().get();
|
auto *oldSF = CI.getCodeCompletionFile();
|
||||||
|
|
||||||
auto *oldState = oldSF->getDelayedParserState();
|
auto *oldState = oldSF->getDelayedParserState();
|
||||||
assert(oldState->hasCodeCompletionDelayedDeclState());
|
assert(oldState->hasCodeCompletionDelayedDeclState());
|
||||||
@@ -304,7 +302,7 @@ bool CompletionInstance::performCachedOperationIfPossible(
|
|||||||
|
|
||||||
if (shouldCheckDependencies()) {
|
if (shouldCheckDependencies()) {
|
||||||
if (areAnyDependentFilesInvalidated(
|
if (areAnyDependentFilesInvalidated(
|
||||||
CI, CurrentModule, *FileSystem, SM.getCodeCompletionBufferID(),
|
CI, *FileSystem, SM.getCodeCompletionBufferID(),
|
||||||
DependencyCheckedTimestamp, InMemoryDependencyHash))
|
DependencyCheckedTimestamp, InMemoryDependencyHash))
|
||||||
return false;
|
return false;
|
||||||
DependencyCheckedTimestamp = std::chrono::system_clock::now();
|
DependencyCheckedTimestamp = std::chrono::system_clock::now();
|
||||||
@@ -441,22 +439,21 @@ bool CompletionInstance::performCachedOperationIfPossible(
|
|||||||
|
|
||||||
// Create a new module and a source file using the current AST context.
|
// Create a new module and a source file using the current AST context.
|
||||||
auto &Ctx = oldM->getASTContext();
|
auto &Ctx = oldM->getASTContext();
|
||||||
auto *newM =
|
auto *newM = ModuleDecl::createMainModule(Ctx, oldM->getName(),
|
||||||
ModuleDecl::create(oldM->getName(), Ctx, oldM->getImplicitImportInfo());
|
oldM->getImplicitImportInfo());
|
||||||
auto *newSF =
|
auto *newSF =
|
||||||
new (Ctx) SourceFile(*newM, SourceFileKind::Main, newBufferID);
|
new (Ctx) SourceFile(*newM, SourceFileKind::Main, newBufferID);
|
||||||
newM->addFile(*newSF);
|
newM->addFile(*newSF);
|
||||||
newSF->enableInterfaceHash();
|
newSF->enableInterfaceHash();
|
||||||
|
|
||||||
// Tell the compiler instance we've replaced the code completion file.
|
// Tell the compiler instance we've replaced the main module.
|
||||||
CI.setCodeCompletionFile(newSF);
|
CI.setMainModule(newM);
|
||||||
|
|
||||||
// Re-process the whole file (parsing will be lazily triggered). Still
|
// Re-process the whole file (parsing will be lazily triggered). Still
|
||||||
// re-use imported modules.
|
// re-use imported modules.
|
||||||
performImportResolution(*newSF);
|
performImportResolution(*newSF);
|
||||||
bindExtensions(*newM);
|
bindExtensions(*newM);
|
||||||
|
|
||||||
CurrentModule = newM;
|
|
||||||
traceDC = newM;
|
traceDC = newM;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const auto *reparsedState = newSF->getDelayedParserState();
|
const auto *reparsedState = newSF->getDelayedParserState();
|
||||||
@@ -483,7 +480,7 @@ bool CompletionInstance::performCachedOperationIfPossible(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CachedReuseCount += 1;
|
CachedReuseCount += 1;
|
||||||
cacheDependencyHashIfNeeded(CI, CurrentModule, SM.getCodeCompletionBufferID(),
|
cacheDependencyHashIfNeeded(CI, SM.getCodeCompletionBufferID(),
|
||||||
InMemoryDependencyHash);
|
InMemoryDependencyHash);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -536,8 +533,7 @@ bool CompletionInstance::performNewOperation(
|
|||||||
CI.performParseAndResolveImportsOnly();
|
CI.performParseAndResolveImportsOnly();
|
||||||
|
|
||||||
// If we didn't find a code completion token, bail.
|
// If we didn't find a code completion token, bail.
|
||||||
auto completionFile = CI.getCodeCompletionFile();
|
auto *state = CI.getCodeCompletionFile()->getDelayedParserState();
|
||||||
auto *state = completionFile.get()->getDelayedParserState();
|
|
||||||
if (!state->hasCodeCompletionDelayedDeclState())
|
if (!state->hasCodeCompletionDelayedDeclState())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -554,14 +550,13 @@ bool CompletionInstance::performNewOperation(
|
|||||||
void CompletionInstance::cacheCompilerInstance(
|
void CompletionInstance::cacheCompilerInstance(
|
||||||
std::unique_ptr<CompilerInstance> CI, llvm::hash_code ArgsHash) {
|
std::unique_ptr<CompilerInstance> CI, llvm::hash_code ArgsHash) {
|
||||||
CachedCI = std::move(CI);
|
CachedCI = std::move(CI);
|
||||||
CurrentModule = CachedCI->getMainModule();
|
|
||||||
CachedArgHash = ArgsHash;
|
CachedArgHash = ArgsHash;
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
DependencyCheckedTimestamp = now;
|
DependencyCheckedTimestamp = now;
|
||||||
CachedReuseCount = 0;
|
CachedReuseCount = 0;
|
||||||
InMemoryDependencyHash.clear();
|
InMemoryDependencyHash.clear();
|
||||||
cacheDependencyHashIfNeeded(
|
cacheDependencyHashIfNeeded(
|
||||||
*CachedCI, CurrentModule,
|
*CachedCI,
|
||||||
CachedCI->getASTContext().SourceMgr.getCodeCompletionBufferID(),
|
CachedCI->getASTContext().SourceMgr.getCodeCompletionBufferID(),
|
||||||
InMemoryDependencyHash);
|
InMemoryDependencyHash);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ static bool swiftCodeCompleteImpl(
|
|||||||
SwiftConsumer.setContext(&CI.getASTContext(), &CI.getInvocation(),
|
SwiftConsumer.setContext(&CI.getASTContext(), &CI.getInvocation(),
|
||||||
&CompletionContext);
|
&CompletionContext);
|
||||||
|
|
||||||
auto SF = CI.getCodeCompletionFile();
|
auto *SF = CI.getCodeCompletionFile();
|
||||||
performCodeCompletionSecondPass(*SF.get(), *callbacksFactory);
|
performCodeCompletionSecondPass(*SF, *callbacksFactory);
|
||||||
SwiftConsumer.clearContext();
|
SwiftConsumer.clearContext();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ static bool swiftConformingMethodListImpl(
|
|||||||
ide::makeConformingMethodListCallbacksFactory(ExpectedTypeNames,
|
ide::makeConformingMethodListCallbacksFactory(ExpectedTypeNames,
|
||||||
Consumer));
|
Consumer));
|
||||||
|
|
||||||
auto SF = CI.getCodeCompletionFile();
|
auto *SF = CI.getCodeCompletionFile();
|
||||||
performCodeCompletionSecondPass(*SF.get(), *callbacksFactory);
|
performCodeCompletionSecondPass(*SF, *callbacksFactory);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ static bool swiftTypeContextInfoImpl(
|
|||||||
std::unique_ptr<CodeCompletionCallbacksFactory> callbacksFactory(
|
std::unique_ptr<CodeCompletionCallbacksFactory> callbacksFactory(
|
||||||
ide::makeTypeContextInfoCallbacksFactory(Consumer));
|
ide::makeTypeContextInfoCallbacksFactory(Consumer));
|
||||||
|
|
||||||
auto SF = CI.getCodeCompletionFile();
|
auto *SF = CI.getCodeCompletionFile();
|
||||||
performCodeCompletionSecondPass(*SF.get(), *callbacksFactory);
|
performCodeCompletionSecondPass(*SF, *callbacksFactory);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -794,8 +794,8 @@ static bool doCodeCompletionImpl(
|
|||||||
CodeCompletionDiagnostics ? &PrintDiags : nullptr,
|
CodeCompletionDiagnostics ? &PrintDiags : nullptr,
|
||||||
[&](CompilerInstance &CI, bool reusingASTContext) {
|
[&](CompilerInstance &CI, bool reusingASTContext) {
|
||||||
assert(!reusingASTContext && "reusing AST context without enabling it");
|
assert(!reusingASTContext && "reusing AST context without enabling it");
|
||||||
auto SF = CI.getCodeCompletionFile();
|
auto *SF = CI.getCodeCompletionFile();
|
||||||
performCodeCompletionSecondPass(*SF.get(), *callbacksFactory);
|
performCodeCompletionSecondPass(*SF, *callbacksFactory);
|
||||||
});
|
});
|
||||||
return isSuccess ? 0 : 1;
|
return isSuccess ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user