Skip to content

Commit 7734344

Browse files
authored
Merge pull request #9395 from benlangmuir/no-cancel-cursor
[cursor-info] Add a way to opt out of automatic request cancellation
2 parents 166d388 + d13b1c7 commit 7734344

File tree

13 files changed

+161
-42
lines changed

13 files changed

+161
-42
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
func myFunc() {
2+
_ = 1
3+
}
4+
5+
// Perform 8 concurrent cursor infos, which is often enough to cause
6+
// contention. We disable printing the requests to minimize delay.
7+
8+
// RUN: %sourcekitd-test \
9+
// RUN: -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
10+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
11+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
12+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
13+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
14+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
15+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
16+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s 2>&1 \
17+
// RUN: | %FileCheck %s -implicit-check-not='Request Cancel'
18+
19+
// CHECK: source.lang.swift.decl.function.free
20+
// CHECK: source.lang.swift.decl.function.free
21+
// CHECK: source.lang.swift.decl.function.free
22+
// CHECK: source.lang.swift.decl.function.free
23+
// CHECK: source.lang.swift.decl.function.free
24+
// CHECK: source.lang.swift.decl.function.free
25+
// CHECK: source.lang.swift.decl.function.free
26+
// CHECK: source.lang.swift.decl.function.free
27+
28+
// RUN: %sourcekitd-test \
29+
// RUN: -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
30+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
31+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
32+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
33+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
34+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
35+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
36+
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s 2>&1 \
37+
// RUN: | %FileCheck %s -check-prefix=RANGE -implicit-check-not='Request Cancel'
38+
39+
// RANGE: source.lang.swift.range.singleexpression
40+
// RANGE: source.lang.swift.range.singleexpression
41+
// RANGE: source.lang.swift.range.singleexpression
42+
// RANGE: source.lang.swift.range.singleexpression
43+
// RANGE: source.lang.swift.range.singleexpression
44+
// RANGE: source.lang.swift.range.singleexpression
45+
// RANGE: source.lang.swift.range.singleexpression
46+
// RANGE: source.lang.swift.range.singleexpression

tools/SourceKit/docs/Protocol.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,10 @@ To gather documentation, SourceKit must be given either the name of a module (ke
635635
[opt] <key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
636636
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
637637
// these must include the path to that file.
638+
[opt] <key.cancel_on_subsequent_request>: (int64) // Whether this request should be canceled if a
639+
// new cursor-info request is made that uses the same AST.
640+
// This behaviour is a workaround for not having first-class
641+
// cancelation. For backwards compatibility, the default is 1.
638642
}
639643
```
640644

tools/SourceKit/include/SourceKit/Core/LangSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ class LangSupport {
475475

476476
virtual void getCursorInfo(StringRef Filename, unsigned Offset,
477477
unsigned Length, bool Actionables,
478+
bool CancelOnSubsequentRequest,
478479
ArrayRef<const char *> Args,
479480
std::function<void(const CursorInfo &)> Receiver) = 0;
480481

@@ -485,16 +486,19 @@ class LangSupport {
485486
std::function<void(const NameTranslatingInfo &)> Receiver) = 0;
486487

487488
virtual void getRangeInfo(StringRef Filename, unsigned Offset, unsigned Length,
489+
bool CancelOnSubsequentRequest,
488490
ArrayRef<const char *> Args,
489491
std::function<void(const RangeInfo&)> Receiver) = 0;
490492

491493
virtual void
492494
getCursorInfoFromUSR(StringRef Filename, StringRef USR,
495+
bool CancelOnSubsequentRequest,
493496
ArrayRef<const char *> Args,
494497
std::function<void(const CursorInfo &)> Receiver) = 0;
495498

496499
virtual void findRelatedIdentifiersInFile(StringRef Filename,
497500
unsigned Offset,
501+
bool CancelOnSubsequentRequest,
498502
ArrayRef<const char *> Args,
499503
std::function<void(const RelatedIdentsInfo &)> Receiver) = 0;
500504

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class SwiftLangSupport : public LangSupport {
389389

390390
void getCursorInfo(StringRef Filename, unsigned Offset,
391391
unsigned Length, bool Actionables,
392+
bool CancelOnSubsequentRequest,
392393
ArrayRef<const char *> Args,
393394
std::function<void(const CursorInfo &)> Receiver) override;
394395

@@ -398,14 +399,16 @@ class SwiftLangSupport : public LangSupport {
398399
std::function<void(const NameTranslatingInfo &)> Receiver) override;
399400

400401
void getRangeInfo(StringRef Filename, unsigned Offset, unsigned Length,
401-
ArrayRef<const char *> Args,
402+
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
402403
std::function<void(const RangeInfo&)> Receiver) override;
403404

404405
void getCursorInfoFromUSR(
405-
StringRef Filename, StringRef USR, ArrayRef<const char *> Args,
406+
StringRef Filename, StringRef USR, bool CancelOnSubsequentRequest,
407+
ArrayRef<const char *> Args,
406408
std::function<void(const CursorInfo &)> Receiver) override;
407409

408410
void findRelatedIdentifiersInFile(StringRef Filename, unsigned Offset,
411+
bool CancelOnSubsequentRequest,
409412
ArrayRef<const char *> Args,
410413
std::function<void(const RelatedIdentsInfo &)> Receiver) override;
411414

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,8 @@ class CursorRangeInfoConsumer : public SwiftASTConsumer {
10301030
const bool TryExistingAST;
10311031
SmallVector<ImmutableTextSnapshotRef, 4> PreviousASTSnaps;
10321032

1033+
protected:
1034+
bool CancelOnSubsequentRequest;
10331035
protected:
10341036
ArrayRef<ImmutableTextSnapshotRef> getPreviousASTSnaps() {
10351037
return llvm::makeArrayRef(PreviousASTSnaps);
@@ -1038,9 +1040,10 @@ class CursorRangeInfoConsumer : public SwiftASTConsumer {
10381040
public:
10391041
CursorRangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
10401042
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
1041-
bool TryExistingAST)
1043+
bool TryExistingAST, bool CancelOnSubsequentRequest)
10421044
: Lang(Lang), ASTInvok(ASTInvok),InputFile(InputFile), Offset(Offset),
1043-
Length(Length), TryExistingAST(TryExistingAST) { }
1045+
Length(Length), TryExistingAST(TryExistingAST),
1046+
CancelOnSubsequentRequest(CancelOnSubsequentRequest) {}
10441047

10451048
bool canUseASTWithSnapshots(ArrayRef<ImmutableTextSnapshotRef> Snapshots) override {
10461049
if (!TryExistingAST) {
@@ -1101,6 +1104,7 @@ static void resolveCursor(SwiftLangSupport &Lang,
11011104
unsigned Length, bool Actionables,
11021105
SwiftInvocationRef Invok,
11031106
bool TryExistingAST,
1107+
bool CancelOnSubsequentRequest,
11041108
std::function<void(const CursorInfo &)> Receiver) {
11051109
assert(Invok);
11061110

@@ -1114,9 +1118,11 @@ static void resolveCursor(SwiftLangSupport &Lang,
11141118
SwiftLangSupport &Lang,
11151119
SwiftInvocationRef ASTInvok,
11161120
bool TryExistingAST,
1121+
bool CancelOnSubsequentRequest,
11171122
std::function<void(const CursorInfo &)> Receiver)
11181123
: CursorRangeInfoConsumer(InputFile, Offset, Length, Lang, ASTInvok,
1119-
TryExistingAST), Actionables(Actionables),
1124+
TryExistingAST, CancelOnSubsequentRequest),
1125+
Actionables(Actionables),
11201126
Receiver(std::move(Receiver)){ }
11211127

11221128
void handlePrimaryAST(ASTUnitRef AstUnit) override {
@@ -1167,7 +1173,8 @@ static void resolveCursor(SwiftLangSupport &Lang,
11671173
if (!getPreviousASTSnaps().empty()) {
11681174
// Attempt again using the up-to-date AST.
11691175
resolveCursor(Lang, InputFile, Offset, Length, Actionables, ASTInvok,
1170-
/*TryExistingAST=*/false, Receiver);
1176+
/*TryExistingAST=*/false, CancelOnSubsequentRequest,
1177+
Receiver);
11711178
} else {
11721179
Receiver({});
11731180
}
@@ -1198,11 +1205,16 @@ static void resolveCursor(SwiftLangSupport &Lang,
11981205

11991206
auto Consumer = std::make_shared<CursorInfoConsumer>(
12001207
InputFile, Offset, Length, Actionables, Lang, Invok, TryExistingAST,
1201-
Receiver);
1208+
CancelOnSubsequentRequest, Receiver);
1209+
12021210
/// FIXME: When request cancellation is implemented and Xcode adopts it,
12031211
/// don't use 'OncePerASTToken'.
12041212
static const char OncePerASTToken = 0;
1205-
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
1213+
static const char OncePerASTTokenWithActionables = 0;
1214+
const void *Once = nullptr;
1215+
if (CancelOnSubsequentRequest)
1216+
Once = Actionables ? &OncePerASTTokenWithActionables : &OncePerASTToken;
1217+
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
12061218
}
12071219

12081220
static void resolveName(SwiftLangSupport &Lang, StringRef InputFile,
@@ -1222,8 +1234,9 @@ static void resolveName(SwiftLangSupport &Lang, StringRef InputFile,
12221234
bool TryExistingAST, NameTranslatingInfo Input,
12231235
std::function<void(const NameTranslatingInfo &)> Receiver)
12241236
: CursorRangeInfoConsumer(InputFile, Offset, 0, Lang, ASTInvok,
1225-
TryExistingAST), Input(std::move(Input)),
1226-
Receiver(std::move(Receiver)){ }
1237+
TryExistingAST,
1238+
/*CancelOnSubsequentRequest=*/false),
1239+
Input(std::move(Input)), Receiver(std::move(Receiver)){ }
12271240

12281241
void handlePrimaryAST(ASTUnitRef AstUnit) override {
12291242
auto &CompIns = AstUnit->getCompilerInstance();
@@ -1296,17 +1309,13 @@ static void resolveName(SwiftLangSupport &Lang, StringRef InputFile,
12961309
auto Consumer = std::make_shared<NameInfoConsumer>(
12971310
InputFile, Offset, Lang, Invok, TryExistingAST, Input, Receiver);
12981311

1299-
/// FIXME: When request cancellation is implemented and Xcode adopts it,
1300-
/// don't use 'OncePerASTToken'.
1301-
static const char OncePerASTToken = 0;
1302-
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
1303-
&OncePerASTToken);
1312+
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), nullptr);
13041313
}
13051314

13061315
static void resolveRange(SwiftLangSupport &Lang,
13071316
StringRef InputFile, unsigned Offset, unsigned Length,
13081317
SwiftInvocationRef Invok,
1309-
bool TryExistingAST,
1318+
bool TryExistingAST, bool CancelOnSubsequentRequest,
13101319
std::function<void(const RangeInfo&)> Receiver) {
13111320
assert(Invok);
13121321

@@ -1316,10 +1325,11 @@ static void resolveRange(SwiftLangSupport &Lang,
13161325
public:
13171326
RangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
13181327
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
1319-
bool TryExistingAST,
1328+
bool TryExistingAST, bool CancelOnSubsequentRequest,
13201329
std::function<void(const RangeInfo&)> Receiver)
13211330
: CursorRangeInfoConsumer(InputFile, Offset, Length, Lang, ASTInvok,
1322-
TryExistingAST), Receiver(std::move(Receiver)){ }
1331+
TryExistingAST, CancelOnSubsequentRequest),
1332+
Receiver(std::move(Receiver)){ }
13231333

13241334
void handlePrimaryAST(ASTUnitRef AstUnit) override {
13251335
if (trace::enabled()) {
@@ -1352,7 +1362,8 @@ static void resolveRange(SwiftLangSupport &Lang,
13521362
if (!getPreviousASTSnaps().empty()) {
13531363
// Attempt again using the up-to-date AST.
13541364
resolveRange(Lang, InputFile, Offset, Length, ASTInvok,
1355-
/*TryExistingAST=*/false, Receiver);
1365+
/*TryExistingAST=*/false, CancelOnSubsequentRequest,
1366+
Receiver);
13561367
} else {
13571368
Receiver(Result);
13581369
}
@@ -1373,17 +1384,18 @@ static void resolveRange(SwiftLangSupport &Lang,
13731384
};
13741385

13751386
auto Consumer = std::make_shared<RangeInfoConsumer>(
1376-
InputFile, Offset, Length, Lang, Invok, TryExistingAST, Receiver);
1387+
InputFile, Offset, Length, Lang, Invok, TryExistingAST,
1388+
CancelOnSubsequentRequest, Receiver);
13771389
/// FIXME: When request cancellation is implemented and Xcode adopts it,
13781390
/// don't use 'OncePerASTToken'.
13791391
static const char OncePerASTToken = 0;
1380-
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
1381-
&OncePerASTToken);
1392+
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
1393+
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
13821394
}
13831395

13841396
void SwiftLangSupport::getCursorInfo(
13851397
StringRef InputFile, unsigned Offset, unsigned Length, bool Actionables,
1386-
ArrayRef<const char *> Args,
1398+
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
13871399
std::function<void(const CursorInfo &)> Receiver) {
13881400

13891401
if (auto IFaceGenRef = IFaceGenContexts.get(InputFile)) {
@@ -1433,12 +1445,12 @@ void SwiftLangSupport::getCursorInfo(
14331445
}
14341446

14351447
resolveCursor(*this, InputFile, Offset, Length, Actionables, Invok,
1436-
/*TryExistingAST=*/true, Receiver);
1448+
/*TryExistingAST=*/true, CancelOnSubsequentRequest, Receiver);
14371449
}
14381450

14391451
void SwiftLangSupport::
14401452
getRangeInfo(StringRef InputFile, unsigned Offset, unsigned Length,
1441-
ArrayRef<const char *> Args,
1453+
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
14421454
std::function<void(const RangeInfo&)> Receiver) {
14431455
if (IFaceGenContexts.get(InputFile)) {
14441456
// FIXME: return range info for generated interfaces.
@@ -1458,7 +1470,7 @@ getRangeInfo(StringRef InputFile, unsigned Offset, unsigned Length,
14581470
return;
14591471
}
14601472
resolveRange(*this, InputFile, Offset, Length, Invok, /*TryExistingAST=*/true,
1461-
Receiver);
1473+
CancelOnSubsequentRequest, Receiver);
14621474
}
14631475

14641476
void SwiftLangSupport::
@@ -1517,6 +1529,7 @@ getNameInfo(StringRef InputFile, unsigned Offset, NameTranslatingInfo &Input,
15171529
static void
15181530
resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
15191531
SwiftInvocationRef Invok, bool TryExistingAST,
1532+
bool CancelOnSubsequentRequest,
15201533
std::function<void(const CursorInfo &)> Receiver) {
15211534
assert(Invok);
15221535

@@ -1526,16 +1539,18 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
15261539
SwiftLangSupport &Lang;
15271540
SwiftInvocationRef ASTInvok;
15281541
const bool TryExistingAST;
1542+
bool CancelOnSubsequentRequest;
15291543
std::function<void(const CursorInfo &)> Receiver;
15301544
SmallVector<ImmutableTextSnapshotRef, 4> PreviousASTSnaps;
15311545

15321546
public:
15331547
CursorInfoConsumer(StringRef InputFile, StringRef USR,
15341548
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
1535-
bool TryExistingAST,
1549+
bool TryExistingAST, bool CancelOnSubsequentRequest,
15361550
std::function<void(const CursorInfo &)> Receiver)
15371551
: InputFile(InputFile), USR(USR), Lang(Lang),
15381552
ASTInvok(std::move(ASTInvok)), TryExistingAST(TryExistingAST),
1553+
CancelOnSubsequentRequest(CancelOnSubsequentRequest),
15391554
Receiver(std::move(Receiver)) {}
15401555

15411556
bool canUseASTWithSnapshots(
@@ -1607,7 +1622,8 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
16071622
if (!PreviousASTSnaps.empty()) {
16081623
// Attempt again using the up-to-date AST.
16091624
resolveCursorFromUSR(Lang, InputFile, USR, ASTInvok,
1610-
/*TryExistingAST=*/false, Receiver);
1625+
/*TryExistingAST=*/false,
1626+
CancelOnSubsequentRequest, Receiver);
16111627
} else {
16121628
Receiver({});
16131629
}
@@ -1628,16 +1644,18 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
16281644
};
16291645

16301646
auto Consumer = std::make_shared<CursorInfoConsumer>(
1631-
InputFile, USR, Lang, Invok, TryExistingAST, Receiver);
1647+
InputFile, USR, Lang, Invok, TryExistingAST, CancelOnSubsequentRequest,
1648+
Receiver);
16321649
/// FIXME: When request cancellation is implemented and Xcode adopts it,
16331650
/// don't use 'OncePerASTToken'.
16341651
static const char OncePerASTToken = 0;
1635-
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
1636-
&OncePerASTToken);
1652+
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
1653+
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
16371654
}
16381655

16391656
void SwiftLangSupport::getCursorInfoFromUSR(
1640-
StringRef filename, StringRef USR, ArrayRef<const char *> args,
1657+
StringRef filename, StringRef USR, bool CancelOnSubsequentRequest,
1658+
ArrayRef<const char *> args,
16411659
std::function<void(const CursorInfo &)> receiver) {
16421660
if (auto IFaceGenRef = IFaceGenContexts.get(filename)) {
16431661
LOG_WARN_FUNC("info from usr for generated interface not implemented yet");
@@ -1655,7 +1673,7 @@ void SwiftLangSupport::getCursorInfoFromUSR(
16551673
}
16561674

16571675
resolveCursorFromUSR(*this, filename, USR, invok, /*TryExistingAST=*/true,
1658-
receiver);
1676+
CancelOnSubsequentRequest, receiver);
16591677
}
16601678

16611679
//===----------------------------------------------------------------------===//
@@ -1724,6 +1742,7 @@ class RelatedIdScanner : public SourceEntityWalker {
17241742

17251743
void SwiftLangSupport::findRelatedIdentifiersInFile(
17261744
StringRef InputFile, unsigned Offset,
1745+
bool CancelOnSubsequentRequest,
17271746
ArrayRef<const char *> Args,
17281747
std::function<void(const RelatedIdentsInfo &)> Receiver) {
17291748

@@ -1820,5 +1839,6 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
18201839
/// FIXME: When request cancellation is implemented and Xcode adopts it,
18211840
/// don't use 'OncePerASTToken'.
18221841
static const char OncePerASTToken = 0;
1823-
ASTMgr->processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
1842+
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
1843+
ASTMgr->processASTAsync(Invok, std::move(Consumer), Once);
18241844
}

tools/SourceKit/tools/sourcekitd-test/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ def objc_name : Separate<["-"], "objc-name">,
106106
def objc_selector : Separate<["-"], "objc-selector">,
107107
HelpText<"Objective-C selector name to translate from">;
108108

109+
def cancel_on_subsequent_request : Separate<["-"], "cancel-on-subsequent-request">,
110+
HelpText<"Whether to cancel if there is a subsequent request using the same AST">;
111+
def cancel_on_subsequent_request_EQ : Joined<["-"], "cancel-on-subsequent-request=">,
112+
Alias<cancel_on_subsequent_request>;
113+
109114
def help : Flag<["-", "--"], "help">,
110115
HelpText<"Display available options">;
111116

0 commit comments

Comments
 (0)