Skip to content

Commit 70ad17a

Browse files
authored
Merge pull request swiftlang#28904 from rintaro/ide-completion-rdar58119719
[CodeCompletion] Reduce accumulating memory per fast completion
2 parents 7bb01ed + 108b9c3 commit 70ad17a

File tree

1 file changed

+41
-10
lines changed

1 file changed

+41
-10
lines changed

lib/IDE/CompletionInstance.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/Basic/SourceManager.h"
2222
#include "swift/Driver/FrontendUtil.h"
2323
#include "swift/Frontend/Frontend.h"
24+
#include "swift/Parse/Lexer.h"
2425
#include "swift/Parse/PersistentParserState.h"
2526
#include "swift/Subsystems.h"
2627
#include "llvm/ADT/Hashing.h"
@@ -159,27 +160,27 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
159160
if (oldInfo.Kind != CodeCompletionDelayedDeclKind::FunctionBody)
160161
return false;
161162

162-
auto newBufferID = SM.addMemBufferCopy(completionBuffer);
163-
SM.setCodeCompletionPoint(newBufferID, Offset);
164-
165163
// Parse the new buffer into temporary SourceFile.
164+
SourceManager tmpSM;
165+
auto tmpBufferID = tmpSM.addMemBufferCopy(completionBuffer);
166+
tmpSM.setCodeCompletionPoint(tmpBufferID, Offset);
167+
166168
LangOptions langOpts;
167169
langOpts.DisableParserLookup = true;
168170
TypeCheckerOptions typeckOpts;
169171
SearchPathOptions searchPathOpts;
170-
DiagnosticEngine Diags(SM);
172+
DiagnosticEngine tmpDiags(tmpSM);
171173
std::unique_ptr<ASTContext> Ctx(
172-
ASTContext::get(langOpts, typeckOpts, searchPathOpts, SM, Diags));
174+
ASTContext::get(langOpts, typeckOpts, searchPathOpts, tmpSM, tmpDiags));
173175
registerIDERequestFunctions(Ctx->evaluator);
174176
registerTypeCheckerRequestFunctions(Ctx->evaluator);
175177
ModuleDecl *M = ModuleDecl::create(Identifier(), *Ctx);
176-
unsigned BufferID = SM.getCodeCompletionBufferID();
177178
PersistentParserState newState;
178179
SourceFile *newSF =
179-
new (*Ctx) SourceFile(*M, SourceFileKind::Library, BufferID,
180+
new (*Ctx) SourceFile(*M, SourceFileKind::Library, tmpBufferID,
180181
SourceFile::ImplicitModuleImportKind::None);
181182
newSF->enableInterfaceHash();
182-
parseIntoSourceFileFull(*newSF, BufferID, &newState);
183+
parseIntoSourceFileFull(*newSF, tmpBufferID, &newState);
183184
// Couldn't find any completion token?
184185
if (!newState.hasCodeCompletionDelayedDeclState())
185186
return false;
@@ -208,6 +209,36 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
208209
// OK, we can perform fast completion for this. Update the orignal delayed
209210
// decl state.
210211

212+
// Fast completion keeps the buffer in memory for multiple completions.
213+
// To reduce the consumption, slice the source buffer so it only holds
214+
// the portion that is needed for the second pass.
215+
auto startOffset = newInfo.StartOffset;
216+
if (newInfo.PrevOffset != ~0u)
217+
startOffset = newInfo.PrevOffset;
218+
auto startLoc = tmpSM.getLocForOffset(tmpBufferID, startOffset);
219+
startLoc = Lexer::getLocForStartOfLine(tmpSM, startLoc);
220+
startOffset = tmpSM.getLocOffsetInBuffer(startLoc, tmpBufferID);
221+
222+
auto endOffset = newInfo.EndOffset;
223+
auto endLoc = tmpSM.getLocForOffset(tmpBufferID, endOffset);
224+
endLoc = Lexer::getLocForEndOfToken(tmpSM, endLoc);
225+
endOffset = tmpSM.getLocOffsetInBuffer(endLoc, tmpBufferID);
226+
227+
newInfo.StartOffset -= startOffset;
228+
newInfo.EndOffset -= startOffset;
229+
if (newInfo.PrevOffset != ~0u)
230+
newInfo.PrevOffset -= startOffset;
231+
232+
auto sourceText = completionBuffer->getBuffer().slice(startOffset, endOffset);
233+
auto newOffset = Offset - startOffset;
234+
235+
auto newBufferID =
236+
SM.addMemBufferCopy(sourceText, completionBuffer->getBufferIdentifier());
237+
SM.openVirtualFile(SM.getLocForBufferStart(newBufferID),
238+
tmpSM.getDisplayNameForLoc(startLoc),
239+
tmpSM.getLineAndColumn(startLoc).first - 1);
240+
SM.setCodeCompletionPoint(newBufferID, newOffset);
241+
211242
// Construct dummy scopes. We don't need to restore the original scope
212243
// because they are probably not 'isResolvable()' anyway.
213244
auto &SI = oldState.getScopeInfo();
@@ -227,8 +258,8 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
227258
if (DiagC)
228259
CI.addDiagnosticConsumer(DiagC);
229260

230-
CI.getDiags().diagnose(SM.getLocForOffset(BufferID, newInfo.StartOffset),
231-
diag::completion_reusing_astcontext);
261+
CI.getDiags().diagnose(SM.getLocForOffset(newBufferID, newInfo.StartOffset),
262+
diag::completion_reusing_astcontext);
232263

233264
Callback(CI);
234265

0 commit comments

Comments
 (0)