Skip to content

Commit feaaf39

Browse files
benlangmuirrjmccall
authored andcommitted
[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 78b7bce commit feaaf39

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"
@@ -2088,53 +2087,85 @@ static void printStatistics(sourcekitd_variant_t Info, raw_ostream &OS) {
20882087
});
20892088
}
20902089

2091-
static void initializeRewriteBuffer(StringRef Input,
2092-
clang::RewriteBuffer &RewriteBuf) {
2093-
RewriteBuf.Initialize(Input);
2094-
StringRef CheckStr = "CHECK";
2095-
size_t Pos = 0;
2096-
while (true) {
2097-
Pos = Input.find(CheckStr, Pos);
2098-
if (Pos == StringRef::npos)
2099-
break;
2100-
Pos = Input.substr(0, Pos).rfind("//");
2101-
assert(Pos != StringRef::npos);
2102-
size_t EndLine = Input.find('\n', Pos);
2103-
assert(EndLine != StringRef::npos);
2104-
++EndLine;
2105-
RewriteBuf.RemoveText(Pos, EndLine-Pos);
2106-
Pos = EndLine;
2090+
static std::string initializeSource(StringRef Input) {
2091+
std::string result;
2092+
{
2093+
llvm::raw_string_ostream OS(result);
2094+
StringRef CheckStr = "CHECK";
2095+
size_t Pos = 0;
2096+
while (true) {
2097+
auto checkPos = Input.find(CheckStr, Pos);
2098+
if (checkPos == StringRef::npos)
2099+
break;
2100+
checkPos = Input.substr(0, checkPos).rfind("//");
2101+
assert(checkPos != StringRef::npos);
2102+
size_t EndLine = Input.find('\n', checkPos);
2103+
assert(EndLine != StringRef::npos);
2104+
++EndLine;
2105+
OS << Input.slice(Pos, checkPos);
2106+
Pos = EndLine;
2107+
}
2108+
2109+
OS << Input.slice(Pos, StringRef::npos);
21072110
}
2111+
return result;
21082112
}
21092113

2110-
static std::vector<std::pair<unsigned, unsigned>>
2111-
getPlaceholderRanges(StringRef Source) {
2114+
static Optional<std::pair<unsigned, unsigned>>
2115+
firstPlaceholderRange(StringRef Source, unsigned from) {
21122116
const char *StartPtr = Source.data();
2113-
std::vector<std::pair<unsigned, unsigned>> Ranges;
2117+
Source = Source.drop_front(from);
2118+
21142119
while (true) {
21152120
size_t Pos = Source.find("<#");
21162121
if (Pos == StringRef::npos)
21172122
break;
21182123
unsigned OffsetStart = Source.data() + Pos - StartPtr;
21192124
Source = Source.substr(Pos+2);
2125+
if (Source.startswith("__skip__") || Source.startswith("T##__skip__"))
2126+
continue;
21202127
Pos = Source.find("#>");
21212128
if (Pos == StringRef::npos)
21222129
break;
21232130
unsigned OffsetEnd = Source.data() + Pos + 2 - StartPtr;
21242131
Source = Source.substr(Pos+2);
2125-
Ranges.emplace_back(OffsetStart, OffsetEnd-OffsetStart);
2132+
return std::make_pair(OffsetStart, OffsetEnd-OffsetStart);
21262133
}
2127-
return Ranges;
2134+
return llvm::None;
21282135
}
21292136

21302137
static void expandPlaceholders(llvm::MemoryBuffer *SourceBuf,
21312138
llvm::raw_ostream &OS) {
2132-
clang::RewriteBuffer RewriteBuf;
2133-
initializeRewriteBuffer(SourceBuf->getBuffer(), RewriteBuf);
2134-
auto Ranges = getPlaceholderRanges(SourceBuf->getBuffer());
2135-
for (auto Range : Ranges) {
2136-
unsigned Offset = Range.first;
2137-
unsigned Length = Range.second;
2139+
auto syncEdit = [=](unsigned offset, unsigned length, const char *text) {
2140+
auto SourceBufID = SourceBuf->getBufferIdentifier();
2141+
auto req = sourcekitd_request_dictionary_create(nullptr, nullptr, 0);
2142+
sourcekitd_request_dictionary_set_uid(req, KeyRequest,
2143+
RequestEditorReplaceText);
2144+
sourcekitd_request_dictionary_set_stringbuf(req, KeyName,
2145+
SourceBufID.data(),
2146+
SourceBufID.size());
2147+
sourcekitd_request_dictionary_set_int64(req, KeyOffset, offset);
2148+
sourcekitd_request_dictionary_set_int64(req, KeyLength, length);
2149+
sourcekitd_request_dictionary_set_string(req, KeySourceText, text);
2150+
2151+
sourcekitd_response_t resp = sourcekitd_send_request_sync(req);
2152+
if (sourcekitd_response_is_error(resp)) {
2153+
sourcekitd_response_description_dump(resp);
2154+
exit(1);
2155+
}
2156+
sourcekitd_request_release(req);
2157+
sourcekitd_response_dispose(resp);
2158+
};
2159+
2160+
std::string source = initializeSource(SourceBuf->getBuffer());
2161+
// Sync contents with modified source.
2162+
syncEdit(0, SourceBuf->getBuffer().size(), source.c_str());
2163+
2164+
unsigned cursor = 0;
2165+
2166+
while (auto Range = firstPlaceholderRange(source, cursor)) {
2167+
unsigned Offset = Range->first;
2168+
unsigned Length = Range->second;
21382169
sourcekitd_object_t Exp = sourcekitd_request_dictionary_create(nullptr,
21392170
nullptr, 0);
21402171
sourcekitd_request_dictionary_set_uid(Exp, KeyRequest,
@@ -2156,16 +2187,25 @@ static void expandPlaceholders(llvm::MemoryBuffer *SourceBuf,
21562187
sourcekitd_variant_t Info = sourcekitd_response_get_value(Resp);
21572188
const char *Text = sourcekitd_variant_dictionary_get_string(Info, KeySourceText);
21582189
if (!Text) {
2190+
cursor = Offset + Length;
21592191
sourcekitd_response_dispose(Resp);
21602192
continue;
21612193
}
21622194
unsigned EditOffset = sourcekitd_variant_dictionary_get_int64(Info, KeyOffset);
21632195
unsigned EditLength = sourcekitd_variant_dictionary_get_int64(Info, KeyLength);
2164-
RewriteBuf.ReplaceText(EditOffset, EditLength, Text);
2196+
2197+
// Apply edit locally.
2198+
source.replace(EditOffset, EditLength, Text);
2199+
2200+
// Apply edit on server.
2201+
syncEdit(EditOffset, EditLength, Text);
2202+
2203+
// Adjust cursor to after the edit (we do not expand recursively).
2204+
cursor = EditOffset + strlen(Text);
21652205
sourcekitd_response_dispose(Resp);
21662206
}
21672207

2168-
RewriteBuf.write(OS);
2208+
OS << source;
21692209
}
21702210

21712211
static std::pair<unsigned, unsigned>

0 commit comments

Comments
 (0)