Skip to content

[cursor-info] Add a way to opt out of automatic request cancellation #9395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions test/SourceKit/CursorInfo/cursor_no_cancel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
func myFunc() {
_ = 1
}

// Perform 8 concurrent cursor infos, which is often enough to cause
// contention. We disable printing the requests to minimize delay.

// RUN: %sourcekitd-test \
// RUN: -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=cursor -pos=1:6 %s -- %s 2>&1 \
// RUN: | %FileCheck %s -implicit-check-not='Request Cancel'

// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free
// CHECK: source.lang.swift.decl.function.free

// RUN: %sourcekitd-test \
// RUN: -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s \
// RUN: == -async -dont-print-request -cancel-on-subsequent-request=0 -req=range -pos=2:3 -length=5 %s -- %s 2>&1 \
// RUN: | %FileCheck %s -check-prefix=RANGE -implicit-check-not='Request Cancel'

// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
// RANGE: source.lang.swift.range.singleexpression
4 changes: 4 additions & 0 deletions tools/SourceKit/docs/Protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,10 @@ To gather documentation, SourceKit must be given either the name of a module (ke
[opt] <key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
// these must include the path to that file.
[opt] <key.cancel_on_subsequent_request>: (int64) // Whether this request should be canceled if a
// new cursor-info request is made that uses the same AST.
// This behaviour is a workaround for not having first-class
// cancelation. For backwards compatibility, the default is 1.
}
```

Expand Down
4 changes: 4 additions & 0 deletions tools/SourceKit/include/SourceKit/Core/LangSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ class LangSupport {

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

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

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

virtual void
getCursorInfoFromUSR(StringRef Filename, StringRef USR,
bool CancelOnSubsequentRequest,
ArrayRef<const char *> Args,
std::function<void(const CursorInfo &)> Receiver) = 0;

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

Expand Down
7 changes: 5 additions & 2 deletions tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ class SwiftLangSupport : public LangSupport {

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

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

void getRangeInfo(StringRef Filename, unsigned Offset, unsigned Length,
ArrayRef<const char *> Args,
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
std::function<void(const RangeInfo&)> Receiver) override;

void getCursorInfoFromUSR(
StringRef Filename, StringRef USR, ArrayRef<const char *> Args,
StringRef Filename, StringRef USR, bool CancelOnSubsequentRequest,
ArrayRef<const char *> Args,
std::function<void(const CursorInfo &)> Receiver) override;

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

Expand Down
84 changes: 52 additions & 32 deletions tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,8 @@ class CursorRangeInfoConsumer : public SwiftASTConsumer {
const bool TryExistingAST;
SmallVector<ImmutableTextSnapshotRef, 4> PreviousASTSnaps;

protected:
bool CancelOnSubsequentRequest;
protected:
ArrayRef<ImmutableTextSnapshotRef> getPreviousASTSnaps() {
return llvm::makeArrayRef(PreviousASTSnaps);
Expand All @@ -1038,9 +1040,10 @@ class CursorRangeInfoConsumer : public SwiftASTConsumer {
public:
CursorRangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
bool TryExistingAST)
bool TryExistingAST, bool CancelOnSubsequentRequest)
: Lang(Lang), ASTInvok(ASTInvok),InputFile(InputFile), Offset(Offset),
Length(Length), TryExistingAST(TryExistingAST) { }
Length(Length), TryExistingAST(TryExistingAST),
CancelOnSubsequentRequest(CancelOnSubsequentRequest) {}

bool canUseASTWithSnapshots(ArrayRef<ImmutableTextSnapshotRef> Snapshots) override {
if (!TryExistingAST) {
Expand Down Expand Up @@ -1101,6 +1104,7 @@ static void resolveCursor(SwiftLangSupport &Lang,
unsigned Length, bool Actionables,
SwiftInvocationRef Invok,
bool TryExistingAST,
bool CancelOnSubsequentRequest,
std::function<void(const CursorInfo &)> Receiver) {
assert(Invok);

Expand All @@ -1114,9 +1118,11 @@ static void resolveCursor(SwiftLangSupport &Lang,
SwiftLangSupport &Lang,
SwiftInvocationRef ASTInvok,
bool TryExistingAST,
bool CancelOnSubsequentRequest,
std::function<void(const CursorInfo &)> Receiver)
: CursorRangeInfoConsumer(InputFile, Offset, Length, Lang, ASTInvok,
TryExistingAST), Actionables(Actionables),
TryExistingAST, CancelOnSubsequentRequest),
Actionables(Actionables),
Receiver(std::move(Receiver)){ }

void handlePrimaryAST(ASTUnitRef AstUnit) override {
Expand Down Expand Up @@ -1167,7 +1173,8 @@ static void resolveCursor(SwiftLangSupport &Lang,
if (!getPreviousASTSnaps().empty()) {
// Attempt again using the up-to-date AST.
resolveCursor(Lang, InputFile, Offset, Length, Actionables, ASTInvok,
/*TryExistingAST=*/false, Receiver);
/*TryExistingAST=*/false, CancelOnSubsequentRequest,
Receiver);
} else {
Receiver({});
}
Expand Down Expand Up @@ -1198,11 +1205,16 @@ static void resolveCursor(SwiftLangSupport &Lang,

auto Consumer = std::make_shared<CursorInfoConsumer>(
InputFile, Offset, Length, Actionables, Lang, Invok, TryExistingAST,
Receiver);
CancelOnSubsequentRequest, Receiver);

/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
static const char OncePerASTTokenWithActionables = 0;
const void *Once = nullptr;
if (CancelOnSubsequentRequest)
Once = Actionables ? &OncePerASTTokenWithActionables : &OncePerASTToken;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
}

static void resolveName(SwiftLangSupport &Lang, StringRef InputFile,
Expand All @@ -1222,8 +1234,9 @@ static void resolveName(SwiftLangSupport &Lang, StringRef InputFile,
bool TryExistingAST, NameTranslatingInfo Input,
std::function<void(const NameTranslatingInfo &)> Receiver)
: CursorRangeInfoConsumer(InputFile, Offset, 0, Lang, ASTInvok,
TryExistingAST), Input(std::move(Input)),
Receiver(std::move(Receiver)){ }
TryExistingAST,
/*CancelOnSubsequentRequest=*/false),
Input(std::move(Input)), Receiver(std::move(Receiver)){ }

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

/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
&OncePerASTToken);
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), nullptr);
}

static void resolveRange(SwiftLangSupport &Lang,
StringRef InputFile, unsigned Offset, unsigned Length,
SwiftInvocationRef Invok,
bool TryExistingAST,
bool TryExistingAST, bool CancelOnSubsequentRequest,
std::function<void(const RangeInfo&)> Receiver) {
assert(Invok);

Expand All @@ -1316,10 +1325,11 @@ static void resolveRange(SwiftLangSupport &Lang,
public:
RangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
bool TryExistingAST,
bool TryExistingAST, bool CancelOnSubsequentRequest,
std::function<void(const RangeInfo&)> Receiver)
: CursorRangeInfoConsumer(InputFile, Offset, Length, Lang, ASTInvok,
TryExistingAST), Receiver(std::move(Receiver)){ }
TryExistingAST, CancelOnSubsequentRequest),
Receiver(std::move(Receiver)){ }

void handlePrimaryAST(ASTUnitRef AstUnit) override {
if (trace::enabled()) {
Expand Down Expand Up @@ -1352,7 +1362,8 @@ static void resolveRange(SwiftLangSupport &Lang,
if (!getPreviousASTSnaps().empty()) {
// Attempt again using the up-to-date AST.
resolveRange(Lang, InputFile, Offset, Length, ASTInvok,
/*TryExistingAST=*/false, Receiver);
/*TryExistingAST=*/false, CancelOnSubsequentRequest,
Receiver);
} else {
Receiver(Result);
}
Expand All @@ -1373,17 +1384,18 @@ static void resolveRange(SwiftLangSupport &Lang,
};

auto Consumer = std::make_shared<RangeInfoConsumer>(
InputFile, Offset, Length, Lang, Invok, TryExistingAST, Receiver);
InputFile, Offset, Length, Lang, Invok, TryExistingAST,
CancelOnSubsequentRequest, Receiver);
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
&OncePerASTToken);
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
}

void SwiftLangSupport::getCursorInfo(
StringRef InputFile, unsigned Offset, unsigned Length, bool Actionables,
ArrayRef<const char *> Args,
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
std::function<void(const CursorInfo &)> Receiver) {

if (auto IFaceGenRef = IFaceGenContexts.get(InputFile)) {
Expand Down Expand Up @@ -1433,12 +1445,12 @@ void SwiftLangSupport::getCursorInfo(
}

resolveCursor(*this, InputFile, Offset, Length, Actionables, Invok,
/*TryExistingAST=*/true, Receiver);
/*TryExistingAST=*/true, CancelOnSubsequentRequest, Receiver);
}

void SwiftLangSupport::
getRangeInfo(StringRef InputFile, unsigned Offset, unsigned Length,
ArrayRef<const char *> Args,
bool CancelOnSubsequentRequest, ArrayRef<const char *> Args,
std::function<void(const RangeInfo&)> Receiver) {
if (IFaceGenContexts.get(InputFile)) {
// FIXME: return range info for generated interfaces.
Expand All @@ -1458,7 +1470,7 @@ getRangeInfo(StringRef InputFile, unsigned Offset, unsigned Length,
return;
}
resolveRange(*this, InputFile, Offset, Length, Invok, /*TryExistingAST=*/true,
Receiver);
CancelOnSubsequentRequest, Receiver);
}

void SwiftLangSupport::
Expand Down Expand Up @@ -1517,6 +1529,7 @@ getNameInfo(StringRef InputFile, unsigned Offset, NameTranslatingInfo &Input,
static void
resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
SwiftInvocationRef Invok, bool TryExistingAST,
bool CancelOnSubsequentRequest,
std::function<void(const CursorInfo &)> Receiver) {
assert(Invok);

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

public:
CursorInfoConsumer(StringRef InputFile, StringRef USR,
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
bool TryExistingAST,
bool TryExistingAST, bool CancelOnSubsequentRequest,
std::function<void(const CursorInfo &)> Receiver)
: InputFile(InputFile), USR(USR), Lang(Lang),
ASTInvok(std::move(ASTInvok)), TryExistingAST(TryExistingAST),
CancelOnSubsequentRequest(CancelOnSubsequentRequest),
Receiver(std::move(Receiver)) {}

bool canUseASTWithSnapshots(
Expand Down Expand Up @@ -1607,7 +1622,8 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
if (!PreviousASTSnaps.empty()) {
// Attempt again using the up-to-date AST.
resolveCursorFromUSR(Lang, InputFile, USR, ASTInvok,
/*TryExistingAST=*/false, Receiver);
/*TryExistingAST=*/false,
CancelOnSubsequentRequest, Receiver);
} else {
Receiver({});
}
Expand All @@ -1628,16 +1644,18 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
};

auto Consumer = std::make_shared<CursorInfoConsumer>(
InputFile, USR, Lang, Invok, TryExistingAST, Receiver);
InputFile, USR, Lang, Invok, TryExistingAST, CancelOnSubsequentRequest,
Receiver);
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer),
&OncePerASTToken);
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
Lang.getASTManager().processASTAsync(Invok, std::move(Consumer), Once);
}

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

resolveCursorFromUSR(*this, filename, USR, invok, /*TryExistingAST=*/true,
receiver);
CancelOnSubsequentRequest, receiver);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1724,6 +1742,7 @@ class RelatedIdScanner : public SourceEntityWalker {

void SwiftLangSupport::findRelatedIdentifiersInFile(
StringRef InputFile, unsigned Offset,
bool CancelOnSubsequentRequest,
ArrayRef<const char *> Args,
std::function<void(const RelatedIdentsInfo &)> Receiver) {

Expand Down Expand Up @@ -1820,5 +1839,6 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
ASTMgr->processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
ASTMgr->processASTAsync(Invok, std::move(Consumer), Once);
}
5 changes: 5 additions & 0 deletions tools/SourceKit/tools/sourcekitd-test/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ def objc_name : Separate<["-"], "objc-name">,
def objc_selector : Separate<["-"], "objc-selector">,
HelpText<"Objective-C selector name to translate from">;

def cancel_on_subsequent_request : Separate<["-"], "cancel-on-subsequent-request">,
HelpText<"Whether to cancel if there is a subsequent request using the same AST">;
def cancel_on_subsequent_request_EQ : Joined<["-"], "cancel-on-subsequent-request=">,
Alias<cancel_on_subsequent_request>;

def help : Flag<["-", "--"], "help">,
HelpText<"Display available options">;

Expand Down
Loading