Skip to content

Commit a23c308

Browse files
committed
[sourcekitd-test] Make expand-placeholder iterative
Instead of getting all edits up front using the same source code, apply each replacement before calculating the next. Placeholder expansion is sensitive the surrounding code, so expanding multiple closures separately can give different results from doing so in order. To allow testing that, add a magic placeholder identifier __skip__ to skip expansion during testing. This is also required for handling multiple trailing closures.
1 parent 62331cf commit a23c308

File tree

2 files changed

+93
-36
lines changed

2 files changed

+93
-36
lines changed

test/SourceKit/CodeExpand/code-expand.swift

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,41 @@ func f1() {
6767
// CHECK-NEXT: <#code#>
6868
// CHECK-NEXT: }
6969

70+
// FIXME: whether we get a trailing closure or not depends on the order we
71+
// expand the placeholders.
7072
func f1() {
71-
bar(<#T##d: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
73+
bar(<#T##__skip__: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
7274
}
73-
// CHECK: bar({
74-
// CHECK-NEXT: <#code#>
75-
// CHECK-NEXT: }, {
75+
// CHECK: bar(<#T##__skip__: () -> ()##() -> ()#>, {
7676
// CHECK-NEXT: <#code#>
7777
// CHECK-NEXT: })
7878

79+
func f1() {
80+
bar(<#T##d: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
81+
}
82+
// CHECK: bar({
83+
// CHECK-NEXT: <#code#>
84+
// CHECK-NEXT: }) {
85+
// CHECK-NEXT: <#code#>
86+
// CHECK-NEXT: }
87+
88+
// FIXME: whether we get a trailing closure or not depends on the order we
89+
// expand the placeholders.
90+
func f1() {
91+
bar(a : <#T##__skip__: () -> ()##() -> ()#>, b : <#T##d: () -> ()##() -> ()#>)
92+
}
93+
// CHECK: bar(a : <#T##__skip__: () -> ()##() -> ()#>, b : {
94+
// CHECK-NEXT: <#code#>
95+
// CHECK-NEXT: })
7996

8097
func f1() {
8198
bar(a : <#T##d: () -> ()##() -> ()#>, b : <#T##d: () -> ()##() -> ()#>)
8299
}
83100
// CHECK: bar(a : {
84101
// CHECK-NEXT: <#code#>
85-
// CHECK-NEXT: }, b : {
102+
// CHECK-NEXT: }) {
86103
// CHECK-NEXT: <#code#>
87-
// CHECK-NEXT: })
104+
// CHECK-NEXT: }
88105

89106

90107
func f1() {

tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "SourceKit/Support/Concurrency.h"
1616
#include "TestOptions.h"
1717
#include "swift/Demangling/ManglingMacros.h"
18-
#include "clang/Rewrite/Core/RewriteBuffer.h"
1918
#include "llvm/ADT/ArrayRef.h"
2019
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2120
#include "llvm/ADT/Optional.h"
@@ -2081,53 +2080,85 @@ static void printStatistics(sourcekitd_variant_t Info, raw_ostream &OS) {
20812080
});
20822081
}
20832082

2084-
static void initializeRewriteBuffer(StringRef Input,
2085-
clang::RewriteBuffer &RewriteBuf) {
2086-
RewriteBuf.Initialize(Input);
2087-
StringRef CheckStr = "CHECK";
2088-
size_t Pos = 0;
2089-
while (true) {
2090-
Pos = Input.find(CheckStr, Pos);
2091-
if (Pos == StringRef::npos)
2092-
break;
2093-
Pos = Input.substr(0, Pos).rfind("//");
2094-
assert(Pos != StringRef::npos);
2095-
size_t EndLine = Input.find('\n', Pos);
2096-
assert(EndLine != StringRef::npos);
2097-
++EndLine;
2098-
RewriteBuf.RemoveText(Pos, EndLine-Pos);
2099-
Pos = EndLine;
2083+
static std::string initializeSource(StringRef Input) {
2084+
std::string result;
2085+
{
2086+
llvm::raw_string_ostream OS(result);
2087+
StringRef CheckStr = "CHECK";
2088+
size_t Pos = 0;
2089+
while (true) {
2090+
auto checkPos = Input.find(CheckStr, Pos);
2091+
if (checkPos == StringRef::npos)
2092+
break;
2093+
checkPos = Input.substr(0, checkPos).rfind("//");
2094+
assert(checkPos != StringRef::npos);
2095+
size_t EndLine = Input.find('\n', checkPos);
2096+
assert(EndLine != StringRef::npos);
2097+
++EndLine;
2098+
OS << Input.slice(Pos, checkPos);
2099+
Pos = EndLine;
2100+
}
2101+
2102+
OS << Input.slice(Pos, StringRef::npos);
21002103
}
2104+
return result;
21012105
}
21022106

2103-
static std::vector<std::pair<unsigned, unsigned>>
2104-
getPlaceholderRanges(StringRef Source) {
2107+
static Optional<std::pair<unsigned, unsigned>>
2108+
firstPlaceholderRange(StringRef Source, unsigned from) {
21052109
const char *StartPtr = Source.data();
2106-
std::vector<std::pair<unsigned, unsigned>> Ranges;
2110+
Source = Source.drop_front(from);
2111+
21072112
while (true) {
21082113
size_t Pos = Source.find("<#");
21092114
if (Pos == StringRef::npos)
21102115
break;
21112116
unsigned OffsetStart = Source.data() + Pos - StartPtr;
21122117
Source = Source.substr(Pos+2);
2118+
if (Source.startswith("__skip__") || Source.startswith("T##__skip__"))
2119+
continue;
21132120
Pos = Source.find("#>");
21142121
if (Pos == StringRef::npos)
21152122
break;
21162123
unsigned OffsetEnd = Source.data() + Pos + 2 - StartPtr;
21172124
Source = Source.substr(Pos+2);
2118-
Ranges.emplace_back(OffsetStart, OffsetEnd-OffsetStart);
2125+
return std::make_pair(OffsetStart, OffsetEnd-OffsetStart);
21192126
}
2120-
return Ranges;
2127+
return llvm::None;
21212128
}
21222129

21232130
static void expandPlaceholders(llvm::MemoryBuffer *SourceBuf,
21242131
llvm::raw_ostream &OS) {
2125-
clang::RewriteBuffer RewriteBuf;
2126-
initializeRewriteBuffer(SourceBuf->getBuffer(), RewriteBuf);
2127-
auto Ranges = getPlaceholderRanges(SourceBuf->getBuffer());
2128-
for (auto Range : Ranges) {
2129-
unsigned Offset = Range.first;
2130-
unsigned Length = Range.second;
2132+
auto syncEdit = [=](unsigned offset, unsigned length, const char *text) {
2133+
auto SourceBufID = SourceBuf->getBufferIdentifier();
2134+
auto req = sourcekitd_request_dictionary_create(nullptr, nullptr, 0);
2135+
sourcekitd_request_dictionary_set_uid(req, KeyRequest,
2136+
RequestEditorReplaceText);
2137+
sourcekitd_request_dictionary_set_stringbuf(req, KeyName,
2138+
SourceBufID.data(),
2139+
SourceBufID.size());
2140+
sourcekitd_request_dictionary_set_int64(req, KeyOffset, offset);
2141+
sourcekitd_request_dictionary_set_int64(req, KeyLength, length);
2142+
sourcekitd_request_dictionary_set_string(req, KeySourceText, text);
2143+
2144+
sourcekitd_response_t resp = sourcekitd_send_request_sync(req);
2145+
if (sourcekitd_response_is_error(resp)) {
2146+
sourcekitd_response_description_dump(resp);
2147+
exit(1);
2148+
}
2149+
sourcekitd_request_release(req);
2150+
sourcekitd_response_dispose(resp);
2151+
};
2152+
2153+
std::string source = initializeSource(SourceBuf->getBuffer());
2154+
// Sync contents with modified source.
2155+
syncEdit(0, SourceBuf->getBuffer().size(), source.c_str());
2156+
2157+
unsigned cursor = 0;
2158+
2159+
while (auto Range = firstPlaceholderRange(source, cursor)) {
2160+
unsigned Offset = Range->first;
2161+
unsigned Length = Range->second;
21312162
sourcekitd_object_t Exp = sourcekitd_request_dictionary_create(nullptr,
21322163
nullptr, 0);
21332164
sourcekitd_request_dictionary_set_uid(Exp, KeyRequest,
@@ -2149,16 +2180,25 @@ static void expandPlaceholders(llvm::MemoryBuffer *SourceBuf,
21492180
sourcekitd_variant_t Info = sourcekitd_response_get_value(Resp);
21502181
const char *Text = sourcekitd_variant_dictionary_get_string(Info, KeySourceText);
21512182
if (!Text) {
2183+
cursor = Offset + Length;
21522184
sourcekitd_response_dispose(Resp);
21532185
continue;
21542186
}
21552187
unsigned EditOffset = sourcekitd_variant_dictionary_get_int64(Info, KeyOffset);
21562188
unsigned EditLength = sourcekitd_variant_dictionary_get_int64(Info, KeyLength);
2157-
RewriteBuf.ReplaceText(EditOffset, EditLength, Text);
2189+
2190+
// Apply edit locally.
2191+
source.replace(EditOffset, EditLength, Text);
2192+
2193+
// Apply edit on server.
2194+
syncEdit(EditOffset, EditLength, Text);
2195+
2196+
// Adjust cursor to after the edit (we do not expand recursively).
2197+
cursor = EditOffset + strlen(Text);
21582198
sourcekitd_response_dispose(Resp);
21592199
}
21602200

2161-
RewriteBuf.write(OS);
2201+
OS << source;
21622202
}
21632203

21642204
static std::pair<unsigned, unsigned>

0 commit comments

Comments
 (0)