Skip to content

Commit 3194881

Browse files
authored
Merge pull request #29251 from rintaro/5.2-ide-completion-fastaccessor-rdar58632889
[5.2][CodeCompletion] Enable fast completion within accessors
2 parents 00dd720 + 89a1f63 commit 3194881

File tree

2 files changed

+166
-4
lines changed

2 files changed

+166
-4
lines changed

lib/IDE/CompletionInstance.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@ unsigned findIndexInRange(Decl *D, const Range &Decls) {
6464

6565
/// Return the element at \p N in \p Decls .
6666
template <typename Range> Decl *getElementAt(const Range &Decls, unsigned N) {
67-
assert(std::distance(Decls.begin(), Decls.end()) > N);
68-
auto I = Decls.begin();
69-
std::advance(I, N);
70-
return *I;
67+
for (auto I = Decls.begin(), E = Decls.end(); I != E; ++I) {
68+
if (N == 0)
69+
return *I;
70+
--N;
71+
}
72+
return nullptr;
7173
}
7274

7375
/// Find the equivalent \c DeclContext with \p DC from \p SF AST.
@@ -85,8 +87,24 @@ static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC,
8587
SmallVector<unsigned, 4> IndexStack;
8688
do {
8789
auto *D = newDC->getAsDecl();
90+
if (!D)
91+
return nullptr;
8892
auto *parentDC = newDC->getParent();
8993
unsigned N;
94+
95+
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
96+
// The AST for accessors is like:
97+
// DeclContext -> AbstractStorageDecl -> AccessorDecl
98+
// We need to push the index of the accessor within the accessor list
99+
// of the storage.
100+
auto *storage = accessor->getStorage();
101+
if (!storage)
102+
return nullptr;
103+
auto accessorN = findIndexInRange(accessor, storage->getAllAccessors());
104+
IndexStack.push_back(accessorN);
105+
D = storage;
106+
}
107+
90108
if (auto parentSF = dyn_cast<SourceFile>(parentDC))
91109
N = findIndexInRange(D, parentSF->Decls);
92110
else if (auto parentIDC =
@@ -119,7 +137,15 @@ static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC,
119137
D = getElementAt(parentIDC->getMembers(), N);
120138
else
121139
llvm_unreachable("invalid DC kind for finding equivalent DC (query)");
140+
141+
if (auto storage = dyn_cast<AbstractStorageDecl>(D)) {
142+
auto accessorN = IndexStack.pop_back_val();
143+
D = getElementAt(storage->getAllAccessors(), accessorN);
144+
}
145+
122146
newDC = dyn_cast<DeclContext>(D);
147+
if (!newDC)
148+
return nullptr;
123149
} while (!IndexStack.empty());
124150

125151
assert(newDC->getContextKind() == DC->getContextKind());
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
class Foo {
2+
var x: Int = 0
3+
var y: Int = 0
4+
func fooMethod() {}
5+
}
6+
struct Bar {
7+
var a: Int = 0
8+
var b: Int = 0
9+
func barMethod() {}
10+
}
11+
var globalValImplicit: Foo {
12+
Bar().
13+
}
14+
var globalValGetSet: Foo {
15+
get { Foo(). }
16+
set { Bar(). }
17+
}
18+
19+
enum S {
20+
var foo: Foo
21+
var bar: Bar
22+
var propertyImplicit: Foo {
23+
foo.
24+
}
25+
var propertyGetSet: Foo {
26+
get { bar. }
27+
set { foo. }
28+
}
29+
subscript(idx: Foo) -> Foo {
30+
idx.
31+
}
32+
subscript(idx: Bar) -> Foo {
33+
get { idx. }
34+
set { idx. }
35+
}
36+
}
37+
38+
39+
// Enabled.
40+
// RUN: %sourcekitd-test \
41+
// RUN: -req=track-compiles == \
42+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=12:9 %s -- %s == \
43+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=15:15 %s -- %s == \
44+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=16:15 %s -- %s == \
45+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=23:9 %s -- %s == \
46+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=26:15 %s -- %s == \
47+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=27:15 %s -- %s == \
48+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=30:9 %s -- %s == \
49+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=33:15 %s -- %s == \
50+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=34:15 %s -- %s > %t.response
51+
// RUN: %FileCheck --check-prefix=RESULT %s < %t.response
52+
// RUN: %FileCheck --check-prefix=TRACE %s < %t.response
53+
54+
// globalValImplicit
55+
// RESULT-LABEL: key.results: [
56+
// RESULT-DAG: key.name: "barMethod()"
57+
// RESULT-DAG: key.name: "self"
58+
// RESULT-DAG: key.name: "a"
59+
// RESULT-DAG: key.name: "b"
60+
// RESULT: ]
61+
// globalValGetSet(get)
62+
// RESULT-LABEL: key.results: [
63+
// RESULT-DAG: key.name: "fooMethod()"
64+
// RESULT-DAG: key.name: "self"
65+
// RESULT-DAG: key.name: "x"
66+
// RESULT-DAG: key.name: "y"
67+
// RESULT: ]
68+
// globalValGetSet(set)
69+
// RESULT-LABEL: key.results: [
70+
// RESULT-DAG: key.name: "barMethod()"
71+
// RESULT-DAG: key.name: "self"
72+
// RESULT-DAG: key.name: "a"
73+
// RESULT-DAG: key.name: "b"
74+
// RESULT: ]
75+
// propertyImplicit
76+
// RESULT-LABEL: key.results: [
77+
// RESULT-DAG: key.name: "fooMethod()"
78+
// RESULT-DAG: key.name: "self"
79+
// RESULT-DAG: key.name: "x"
80+
// RESULT-DAG: key.name: "y"
81+
// RESULT: ]
82+
// propertyGetSet(get)
83+
// RESULT-LABEL: key.results: [
84+
// RESULT-DAG: key.name: "barMethod()"
85+
// RESULT-DAG: key.name: "self"
86+
// RESULT-DAG: key.name: "a"
87+
// RESULT-DAG: key.name: "b"
88+
// RESULT: ]
89+
// propertyGetSet(set)
90+
// RESULT-LABEL: key.results: [
91+
// RESULT-DAG: key.name: "fooMethod()"
92+
// RESULT-DAG: key.name: "self"
93+
// RESULT-DAG: key.name: "x"
94+
// RESULT-DAG: key.name: "y"
95+
// RESULT: ]
96+
// subscript(implicit getter)
97+
// RESULT-LABEL: key.results: [
98+
// RESULT-DAG: key.name: "fooMethod()"
99+
// RESULT-DAG: key.name: "self"
100+
// RESULT-DAG: key.name: "x"
101+
// RESULT-DAG: key.name: "y"
102+
// RESULT: ]
103+
// subscript(get)
104+
// RESULT-LABEL: key.results: [
105+
// RESULT-DAG: key.name: "barMethod()"
106+
// RESULT-DAG: key.name: "self"
107+
// RESULT-DAG: key.name: "a"
108+
// RESULT-DAG: key.name: "b"
109+
// RESULT: ]
110+
// subscript(set)
111+
// RESULT-LABEL: key.results: [
112+
// RESULT-DAG: key.name: "barMethod()"
113+
// RESULT-DAG: key.name: "self"
114+
// RESULT-DAG: key.name: "a"
115+
// RESULT-DAG: key.name: "b"
116+
// RESULT: ]
117+
118+
119+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
120+
// TRACE-NOT: key.description: "completion reusing previous ASTContext (benign diagnostic)"
121+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
122+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
123+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
124+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
125+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
126+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
127+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
128+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
129+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
130+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
131+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
132+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
133+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
134+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
135+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
136+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"

0 commit comments

Comments
 (0)