-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathCodeCompletionConsumer.cpp
156 lines (143 loc) · 6.76 KB
/
CodeCompletionConsumer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//===--- CodeCompletionConsumer.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/IDE/CodeCompletionConsumer.h"
#include "swift/IDE/CodeCompletionCache.h"
using namespace swift;
using namespace swift::ide;
static MutableArrayRef<CodeCompletionResult *> copyCodeCompletionResults(
CodeCompletionResultSink &targetSink, CodeCompletionCache::Value &source,
bool onlyTypes, bool onlyPrecedenceGroups,
const ExpectedTypeContext *TypeContext, const DeclContext *DC,
bool CanCurrDeclContextHandleAsync) {
// We will be adding foreign results (from another sink) into TargetSink.
// TargetSink should have an owning pointer to the allocator that keeps the
// results alive.
targetSink.ForeignAllocators.push_back(source.Allocator);
auto startSize = targetSink.Results.size();
std::function<bool(const ContextFreeCodeCompletionResult *)>
shouldIncludeResult;
if (onlyTypes) {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
if (R->getKind() != CodeCompletionResultKind::Declaration)
return false;
switch (R->getAssociatedDeclKind()) {
case CodeCompletionDeclKind::Module:
case CodeCompletionDeclKind::Class:
case CodeCompletionDeclKind::Actor:
case CodeCompletionDeclKind::Struct:
case CodeCompletionDeclKind::Enum:
case CodeCompletionDeclKind::Protocol:
case CodeCompletionDeclKind::TypeAlias:
case CodeCompletionDeclKind::AssociatedType:
case CodeCompletionDeclKind::GenericTypeParam:
return true;
case CodeCompletionDeclKind::PrecedenceGroup:
case CodeCompletionDeclKind::EnumElement:
case CodeCompletionDeclKind::Constructor:
case CodeCompletionDeclKind::Destructor:
case CodeCompletionDeclKind::Subscript:
case CodeCompletionDeclKind::StaticMethod:
case CodeCompletionDeclKind::InstanceMethod:
case CodeCompletionDeclKind::PrefixOperatorFunction:
case CodeCompletionDeclKind::PostfixOperatorFunction:
case CodeCompletionDeclKind::InfixOperatorFunction:
case CodeCompletionDeclKind::FreeFunction:
case CodeCompletionDeclKind::StaticVar:
case CodeCompletionDeclKind::InstanceVar:
case CodeCompletionDeclKind::LocalVar:
case CodeCompletionDeclKind::GlobalVar:
return false;
}
llvm_unreachable("Unhandled CodeCompletionDeclKind in switch.");
};
} else if (onlyPrecedenceGroups) {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
return R->getAssociatedDeclKind() ==
CodeCompletionDeclKind::PrecedenceGroup;
};
} else {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
// PrecedenceGroups are only valid in 'onlyPrecedenceGroups'.
return R->getAssociatedDeclKind() !=
CodeCompletionDeclKind::PrecedenceGroup;
};
}
USRBasedTypeContext USRTypeContext(TypeContext, source.USRTypeArena);
for (auto contextFreeResult : source.Results) {
if (!shouldIncludeResult(contextFreeResult)) {
continue;
}
auto contextualResult = new (*targetSink.Allocator) CodeCompletionResult(
*contextFreeResult, SemanticContextKind::OtherModule,
CodeCompletionFlair(),
/*numBytesToErase=*/0, TypeContext, DC, &USRTypeContext,
CanCurrDeclContextHandleAsync, ContextualNotRecommendedReason::None);
targetSink.Results.push_back(contextualResult);
}
return llvm::makeMutableArrayRef(targetSink.Results.data() + startSize,
targetSink.Results.size() - startSize);
}
void SimpleCachingCodeCompletionConsumer::handleResultsAndModules(
CodeCompletionContext &context,
ArrayRef<RequestedCachedModule> requestedModules,
const ExpectedTypeContext *TypeContext, const DeclContext *DC,
bool CanCurrDeclContextHandleAsync) {
// Use the current SourceFile as the DeclContext so that we can use it to
// perform qualified lookup, and to get the correct visibility for
// @testable imports. Also it cannot use 'DC' since it would apply decl
// context changes to cached results.
const SourceFile *SF = DC->getParentSourceFile();
for (auto &R : requestedModules) {
// FIXME(thread-safety): lock the whole AST context. We might load a
// module.
llvm::Optional<CodeCompletionCache::ValueRefCntPtr> V =
context.Cache.get(R.Key);
if (!V.hasValue()) {
// No cached results found. Fill the cache.
V = context.Cache.createValue();
// Temporary sink in which we gather the result. The cache value retains
// the sink's allocator.
CodeCompletionResultSink Sink;
Sink.annotateResult = context.getAnnotateResult();
Sink.addInitsToTopLevel = context.getAddInitsToTopLevel();
Sink.enableCallPatternHeuristics = context.getCallPatternHeuristics();
Sink.includeObjectLiterals = context.includeObjectLiterals();
Sink.addCallWithNoDefaultArgs = context.addCallWithNoDefaultArgs();
Sink.setProduceContextFreeResults((*V)->USRTypeArena);
lookupCodeCompletionResultsFromModule(Sink, R.TheModule, R.Key.AccessPath,
R.Key.ResultsHaveLeadingDot, SF);
(*V)->Allocator = Sink.Allocator;
auto &CachedResults = (*V)->Results;
CachedResults.reserve(Sink.Results.size());
// Instead of copying the context free results out of the sink's allocator
// retain the sink's entire allocator (which also includes the contextual
// properities) and simply store pointers to the context free results that
// back the contextual results.
for (auto Result : Sink.Results) {
assert(
Result->getContextFreeResult().getResultType().isBackedByUSRs() &&
"Results stored in the cache should have their result types backed "
"by a USR because the cache might outlive the ASTContext the "
"results were created from.");
CachedResults.push_back(&Result->getContextFreeResult());
}
context.Cache.set(R.Key, *V);
}
assert(V.hasValue());
auto newItems = copyCodeCompletionResults(
context.getResultSink(), **V, R.OnlyTypes, R.OnlyPrecedenceGroups,
TypeContext, DC, CanCurrDeclContextHandleAsync);
postProcessCompletionResults(newItems, context.CodeCompletionKind, DC,
&context.getResultSink());
}
handleResults(context);
}