Skip to content

Commit df73082

Browse files
committed
[Code Completion] Split code completion results into context free part that can be cached and contextual part displayed to the user
This allows makes the distinction between cachable and non-cachable properties cleaner and allows us to more easily compute contextual information (like type relations) for cached items later.
1 parent 5441e7a commit df73082

12 files changed

+825
-588
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 358 additions & 202 deletions
Large diffs are not rendered by default.

include/swift/IDE/CodeCompletionCache.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,16 @@ class CodeCompletionCache {
5858
};
5959

6060
struct Value : public llvm::ThreadSafeRefCountedBase<Value> {
61+
using AllocatorPtr = std::shared_ptr<llvm::BumpPtrAllocator>;
62+
63+
/// The allocator used to allocate the results stored in this cache.
64+
AllocatorPtr Allocator;
65+
6166
llvm::sys::TimePoint<> ModuleModificationTime;
62-
CodeCompletionResultSink Sink;
67+
68+
std::vector<ContextFreeCodeCompletionResult *> Results;
69+
70+
Value() : Allocator(std::make_shared<llvm::BumpPtrAllocator>()) {}
6371
};
6472
using ValueRefCntPtr = llvm::IntrusiveRefCntPtr<Value>;
6573

lib/IDE/CodeCompletion.cpp

Lines changed: 277 additions & 255 deletions
Large diffs are not rendered by default.

lib/IDE/CodeCompletionCache.cpp

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace swift {
4141
struct CacheValueCostInfo<swift::ide::CodeCompletionCacheImpl::Value> {
4242
static size_t
4343
getCost(const swift::ide::CodeCompletionCacheImpl::Value &V) {
44-
return V.Sink.Allocator->getTotalMemory();
44+
return V.Allocator->getTotalMemory();
4545
}
4646
};
4747
} // namespace sys
@@ -102,7 +102,8 @@ CodeCompletionCache::~CodeCompletionCache() {}
102102
///
103103
/// This should be incremented any time we commit a change to the format of the
104104
/// cached results. This isn't expected to change very often.
105-
static constexpr uint32_t onDiskCompletionCacheVersion = 3; // Removed "source file path".
105+
static constexpr uint32_t onDiskCompletionCacheVersion =
106+
4; // Store ContextFreeCodeCompletionResults in cache
106107

107108
/// Deserializes CodeCompletionResults from \p in and stores them in \p V.
108109
/// \see writeCacheModule.
@@ -166,7 +167,7 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
166167

167168
const char *p = strings + index;
168169
auto size = read32le(p);
169-
auto str = copyString(*V.Sink.Allocator, StringRef(p, size));
170+
auto str = copyString(*V.Allocator, StringRef(p, size));
170171
knownStrings[index] = str;
171172
return str;
172173
};
@@ -192,21 +193,19 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
192193
}
193194
}
194195

195-
return CodeCompletionString::create(*V.Sink.Allocator, chunkList);
196+
return CodeCompletionString::create(*V.Allocator, chunkList);
196197
};
197198

198199
// RESULTS
199200
while (cursor != resultEnd) {
200-
auto kind = static_cast<CodeCompletionResult::ResultKind>(*cursor++);
201+
auto kind = static_cast<CodeCompletionResultKind>(*cursor++);
201202
auto declKind = static_cast<CodeCompletionDeclKind>(*cursor++);
202203
auto opKind = static_cast<CodeCompletionOperatorKind>(*cursor++);
203-
auto context = static_cast<SemanticContextKind>(*cursor++);
204204
auto notRecommended =
205-
static_cast<CodeCompletionResult::NotRecommendedReason>(*cursor++);
205+
static_cast<ContextFreeNotRecommendedReason>(*cursor++);
206206
auto diagSeverity =
207207
static_cast<CodeCompletionDiagnosticSeverity>(*cursor++);
208208
auto isSystem = static_cast<bool>(*cursor++);
209-
auto numBytesToErase = static_cast<unsigned>(*cursor++);
210209
auto chunkIndex = read32le(cursor);
211210
auto moduleIndex = read32le(cursor);
212211
auto briefDocIndex = read32le(cursor);
@@ -223,21 +222,20 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
223222
auto briefDocComment = getString(briefDocIndex);
224223
auto diagMessage = getString(diagMessageIndex);
225224

226-
CodeCompletionResult *result = nullptr;
227-
if (kind == CodeCompletionResult::ResultKind::Declaration) {
228-
result = new (*V.Sink.Allocator) CodeCompletionResult(
229-
context, CodeCompletionFlair(), numBytesToErase, string, declKind,
230-
isSystem, moduleName, notRecommended, diagSeverity, diagMessage,
231-
briefDocComment,
232-
copyArray(*V.Sink.Allocator, ArrayRef<StringRef>(assocUSRs)),
233-
CodeCompletionResult::ExpectedTypeRelation::Unknown, opKind);
225+
ContextFreeCodeCompletionResult *result = nullptr;
226+
if (kind == CodeCompletionResultKind::Declaration) {
227+
result = new (*V.Allocator) ContextFreeCodeCompletionResult(
228+
CodeCompletionResultKind::Declaration, static_cast<uint8_t>(declKind),
229+
opKind, isSystem, string, moduleName, briefDocComment,
230+
copyArray(*V.Allocator, ArrayRef<StringRef>(assocUSRs)),
231+
notRecommended, diagSeverity, diagMessage);
234232
} else {
235-
result = new (*V.Sink.Allocator) CodeCompletionResult(
236-
kind, context, CodeCompletionFlair(), numBytesToErase, string,
237-
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, opKind);
233+
result = new (*V.Allocator) ContextFreeCodeCompletionResult(
234+
kind, string, opKind, /*BriefDocComment=*/"", notRecommended,
235+
diagSeverity, diagMessage);
238236
}
239237

240-
V.Sink.Results.push_back(result);
238+
V.Results.push_back(result);
241239
}
242240

243241
return true;
@@ -342,27 +340,22 @@ static void writeCachedModule(llvm::raw_ostream &out,
342340
// RESULTS
343341
{
344342
endian::Writer LE(results, little);
345-
for (CodeCompletionResult *R : V.Sink.Results) {
346-
assert(!R->getFlair().toRaw() && "Any flairs should not be cached");
347-
assert(R->getNotRecommendedReason() !=
348-
CodeCompletionResult::NotRecommendedReason::InvalidAsyncContext &&
349-
"InvalidAsyncContext is decl context specific, cannot be cached");
350-
343+
for (ContextFreeCodeCompletionResult *R : V.Results) {
351344
// FIXME: compress bitfield
352345
LE.write(static_cast<uint8_t>(R->getKind()));
353-
if (R->getKind() == CodeCompletionResult::ResultKind::Declaration)
346+
if (R->getKind() == CodeCompletionResultKind::Declaration) {
354347
LE.write(static_cast<uint8_t>(R->getAssociatedDeclKind()));
355-
else
348+
} else {
356349
LE.write(static_cast<uint8_t>(~0u));
357-
if (R->isOperator())
358-
LE.write(static_cast<uint8_t>(R->getOperatorKind()));
359-
else
350+
}
351+
if (R->isOperator()) {
352+
LE.write(static_cast<uint8_t>(R->getKnownOperatorKind()));
353+
} else {
360354
LE.write(static_cast<uint8_t>(CodeCompletionOperatorKind::None));
361-
LE.write(static_cast<uint8_t>(R->getSemanticContext()));
355+
}
362356
LE.write(static_cast<uint8_t>(R->getNotRecommendedReason()));
363357
LE.write(static_cast<uint8_t>(R->getDiagnosticSeverity()));
364358
LE.write(static_cast<uint8_t>(R->isSystem()));
365-
LE.write(static_cast<uint8_t>(R->getNumBytesToErase()));
366359
LE.write(
367360
static_cast<uint32_t>(addCompletionString(R->getCompletionString())));
368361
LE.write(addString(R->getModuleName())); // index into strings

lib/IDE/CodeCompletionDiagnostics.cpp

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -144,37 +144,44 @@ bool CodeCompletionDiagnostics::getDiagnosticForDeprecated(
144144

145145
} // namespace
146146

147-
bool swift::ide::getCompletionDiagnostics(
148-
CodeCompletionResult::NotRecommendedReason reason, const ValueDecl *D,
149-
CodeCompletionDiagnosticSeverity &severity, llvm::raw_ostream &Out) {
150-
using NotRecommendedReason = CodeCompletionResult::NotRecommendedReason;
151-
152-
ASTContext &ctx = D->getASTContext();
153-
154-
CodeCompletionDiagnostics Diag(ctx);
155-
switch (reason) {
156-
case NotRecommendedReason::Deprecated:
157-
case NotRecommendedReason::SoftDeprecated:
158-
return Diag.getDiagnosticForDeprecated(D, severity, Out);
159-
case NotRecommendedReason::InvalidAsyncContext:
160-
// FIXME: Could we use 'diag::async_in_nonasync_function'?
161-
return Diag.getDiagnostics(severity, Out, diag::ide_async_in_nonasync_context,
162-
D->getName());
163-
case NotRecommendedReason::CrossActorReference:
164-
return Diag.getDiagnostics(severity, Out, diag::ide_cross_actor_reference_swift5,
165-
D->getName());
166-
case NotRecommendedReason::RedundantImport:
167-
return Diag.getDiagnostics(severity, Out, diag::ide_redundant_import,
168-
D->getName());
169-
case NotRecommendedReason::RedundantImportIndirect:
170-
return Diag.getDiagnostics(severity, Out, diag::ide_redundant_import_indirect,
171-
D->getName());
172-
case NotRecommendedReason::VariableUsedInOwnDefinition:
173-
return Diag.getDiagnostics(severity, Out, diag::recursive_accessor_reference,
174-
D->getName().getBaseIdentifier(), /*"getter"*/ 0);
175-
case NotRecommendedReason::None:
147+
bool swift::ide::getContextFreeCompletionDiagnostics(
148+
ContextFreeNotRecommendedReason Reason, const ValueDecl *D,
149+
CodeCompletionDiagnosticSeverity &Severity, llvm::raw_ostream &Out) {
150+
CodeCompletionDiagnostics Diag(D->getASTContext());
151+
switch (Reason) {
152+
case ContextFreeNotRecommendedReason::Deprecated:
153+
case ContextFreeNotRecommendedReason::SoftDeprecated:
154+
return Diag.getDiagnosticForDeprecated(D, Severity, Out);
155+
case ContextFreeNotRecommendedReason::None:
176156
llvm_unreachable("invalid not recommended reason");
177157
}
178158
return true;
179159
}
180160

161+
bool swift::ide::getContextualCompletionDiagnostics(
162+
ContextualNotRecommendedReason Reason, const ValueDecl *D,
163+
CodeCompletionDiagnosticSeverity &Severity, llvm::raw_ostream &Out) {
164+
CodeCompletionDiagnostics Diag(D->getASTContext());
165+
switch (Reason) {
166+
case ContextualNotRecommendedReason::InvalidAsyncContext:
167+
// FIXME: Could we use 'diag::async_in_nonasync_function'?
168+
return Diag.getDiagnostics(
169+
Severity, Out, diag::ide_async_in_nonasync_context, D->getName());
170+
case ContextualNotRecommendedReason::CrossActorReference:
171+
return Diag.getDiagnostics(
172+
Severity, Out, diag::ide_cross_actor_reference_swift5, D->getName());
173+
case ContextualNotRecommendedReason::RedundantImport:
174+
return Diag.getDiagnostics(Severity, Out, diag::ide_redundant_import,
175+
D->getName());
176+
case ContextualNotRecommendedReason::RedundantImportIndirect:
177+
return Diag.getDiagnostics(
178+
Severity, Out, diag::ide_redundant_import_indirect, D->getName());
179+
case ContextualNotRecommendedReason::VariableUsedInOwnDefinition:
180+
return Diag.getDiagnostics(
181+
Severity, Out, diag::recursive_accessor_reference,
182+
D->getName().getBaseIdentifier(), /*"getter"*/ 0);
183+
case ContextualNotRecommendedReason::None:
184+
llvm_unreachable("invalid not recommended reason");
185+
}
186+
return true;
187+
}

lib/IDE/CodeCompletionDiagnostics.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,21 @@ class ValueDecl;
2121

2222
namespace ide {
2323

24-
/// Populate \p severity and \p Out with the diagnostics for \p D.
24+
/// Populate \p severity and \p Out with the context-free diagnostics for \p D.
25+
/// See \c NotRecommendedReason for an explaination of context-free vs.
26+
/// contextual diagnostics.
2527
/// Returns \c true if it fails to generate the diagnostics.
26-
bool getCompletionDiagnostics(CodeCompletionResult::NotRecommendedReason reason,
27-
const ValueDecl *D,
28-
CodeCompletionDiagnosticSeverity &severity,
29-
llvm::raw_ostream &Out);
28+
bool getContextFreeCompletionDiagnostics(
29+
ContextFreeNotRecommendedReason reason, const ValueDecl *D,
30+
CodeCompletionDiagnosticSeverity &severity, llvm::raw_ostream &Out);
31+
32+
/// Populate \p severity and \p Out with the contextual diagnostics for \p D.
33+
/// See \c NotRecommendedReason for an explaination of context-free vs.
34+
/// contextual diagnostics.
35+
/// Returns \c true if it fails to generate the diagnostics.
36+
bool getContextualCompletionDiagnostics(
37+
ContextualNotRecommendedReason reason, const ValueDecl *D,
38+
CodeCompletionDiagnosticSeverity &severity, llvm::raw_ostream &Out);
3039

3140
} // namespace ide
3241
} // namespace swift

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class CodeCompletionResultBuilder {
7474
friend CodeCompletionStringPrinter;
7575

7676
CodeCompletionResultSink &Sink;
77-
CodeCompletionResult::ResultKind Kind;
77+
CodeCompletionResultKind Kind;
7878
SemanticContextKind SemanticContext;
7979
CodeCompletionFlair Flair;
8080
unsigned NumBytesToErase = 0;
@@ -89,8 +89,10 @@ class CodeCompletionResultBuilder {
8989
CodeCompletionResult::ExpectedTypeRelation ExpectedTypeRelation =
9090
CodeCompletionResult::ExpectedTypeRelation::Unknown;
9191
bool Cancelled = false;
92-
CodeCompletionResult::NotRecommendedReason NotRecReason =
93-
CodeCompletionResult::NotRecommendedReason::None;
92+
ContextFreeNotRecommendedReason ContextFreeNotRecReason =
93+
ContextFreeNotRecommendedReason::None;
94+
ContextualNotRecommendedReason ContextualNotRecReason =
95+
ContextualNotRecommendedReason::None;
9496
StringRef BriefDocComment;
9597

9698
void addChunkWithText(CodeCompletionString::Chunk::ChunkKind Kind,
@@ -117,7 +119,7 @@ class CodeCompletionResultBuilder {
117119

118120
public:
119121
CodeCompletionResultBuilder(CodeCompletionResultSink &Sink,
120-
CodeCompletionResult::ResultKind Kind,
122+
CodeCompletionResultKind Kind,
121123
SemanticContextKind SemanticContext,
122124
const ExpectedTypeContext &declTypeContext)
123125
: Sink(Sink), Kind(Kind), SemanticContext(SemanticContext),
@@ -146,12 +148,11 @@ class CodeCompletionResultBuilder {
146148

147149
void setLiteralKind(CodeCompletionLiteralKind kind) { LiteralKind = kind; }
148150
void setKeywordKind(CodeCompletionKeywordKind kind) { KeywordKind = kind; }
149-
void setNotRecommended(CodeCompletionResult::NotRecommendedReason Reason) {
150-
NotRecReason = Reason;
151+
void setContextFreeNotRecommended(ContextFreeNotRecommendedReason Reason) {
152+
ContextFreeNotRecReason = Reason;
151153
}
152-
153-
void setSemanticContext(SemanticContextKind Kind) {
154-
SemanticContext = Kind;
154+
void setContextualNotRecommended(ContextualNotRecommendedReason Reason) {
155+
ContextualNotRecReason = Reason;
155156
}
156157

157158
void addFlair(CodeCompletionFlair Options) {

lib/IDE/REPLCodeCompletion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ static void toDisplayString(CodeCompletionResult *Result,
121121
}
122122
if (C.is(CodeCompletionString::Chunk::ChunkKind::TypeAnnotation) ||
123123
C.is(CodeCompletionString::Chunk::ChunkKind::TypeAnnotationBegin)) {
124-
if (Result->getKind() == CodeCompletionResult::ResultKind::Declaration) {
124+
if (Result->getKind() == CodeCompletionResultKind::Declaration) {
125125
switch (Result->getAssociatedDeclKind()) {
126126
case CodeCompletionDeclKind::Module:
127127
case CodeCompletionDeclKind::PrecedenceGroup:

0 commit comments

Comments
 (0)