Skip to content

Commit 40573ad

Browse files
authored
Merge pull request #63816 from apple/louisd/sourcekit-inactive-ranges-request
[SourceKit] Add "Active Regions" request
2 parents 360c6d1 + 876682f commit 40573ad

File tree

11 files changed

+279
-0
lines changed

11 files changed

+279
-0
lines changed

Diff for: test/SourceKit/ActiveRegions/nested.swift

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#if FLAG_1
2+
class Foo {
3+
#if FLAG_2
4+
func debugOnly() {
5+
6+
}
7+
#endif
8+
}
9+
#elseif FLAG_3
10+
class GracefulFallback {
11+
12+
}
13+
#else
14+
class Fallback {
15+
16+
}
17+
#endif
18+
19+
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
20+
// CHECK1: START IF CONFIGS
21+
// CHECK1-NEXT: 1:1 - active
22+
// CHECK1-NEXT: 3:5 - inactive
23+
// CHECK1-NEXT: 9:1 - inactive
24+
// CHECK1-NEXT: 13:1 - inactive
25+
// CHECK1-NEXT: END IF CONFIGS
26+
27+
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_2 -module-name active_regions %s | %FileCheck -check-prefix=CHECK2 %s
28+
// CHECK2: START IF CONFIGS
29+
// CHECK2-NEXT: 1:1 - inactive
30+
// CHECK2-NEXT: 9:1 - inactive
31+
// CHECK2-NEXT: 13:1 - active
32+
// CHECK2-NEXT: END IF CONFIGS
33+
34+
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -D FLAG_2 -module-name active_regions %s | %FileCheck -check-prefix=CHECK3 %s
35+
// CHECK3: START IF CONFIGS
36+
// CHECK3-NEXT: 1:1 - active
37+
// CHECK3-NEXT: 3:5 - active
38+
// CHECK3-NEXT: 9:1 - inactive
39+
// CHECK3-NEXT: 13:1 - inactive
40+
// CHECK3-NEXT: END IF CONFIGS
41+
42+
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_3 -module-name active_regions %s | %FileCheck -check-prefix=CHECK4 %s
43+
// CHECK4: START IF CONFIGS
44+
// CHECK4-NEXT: 1:1 - inactive
45+
// CHECK4-NEXT: 9:1 - active
46+
// CHECK4-NEXT: 13:1 - inactive
47+
// CHECK4-NEXT: END IF CONFIGS
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#if FOO > 10
2+
class Foo {
3+
}
4+
#else
5+
class Fallback {
6+
}
7+
#endif
8+
// RUN: %sourcekitd-test -req=active-regions %s -- -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
9+
// CHECK1: START IF CONFIGS
10+
// CHECK1-NEXT: 1:1 - inactive
11+
// CHECK1-NEXT: 4:1 - active
12+
// CHECK1-NEXT: END IF CONFIGS

Diff for: test/SourceKit/ActiveRegions/unterminated.swift

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#if FLAG_1
2+
class Foo {
3+
}
4+
#else
5+
class Fallback {
6+
}
7+
8+
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
9+
// CHECK1: START IF CONFIGS
10+
// CHECK1-NEXT: 1:1 - active
11+
// CHECK1-NEXT: 4:1 - inactive
12+
// CHECK1-NEXT: END IF CONFIGS

Diff for: tools/SourceKit/include/SourceKit/Core/LangSupport.h

+20
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,20 @@ struct RelatedIdentsInfo {
648648
ArrayRef<std::pair<unsigned, unsigned>> Ranges;
649649
};
650650

651+
/// Represent one branch of an if config.
652+
/// Either `#if`, `#else` or `#elseif`.
653+
struct IfConfigInfo {
654+
unsigned Offset;
655+
bool IsActive;
656+
657+
IfConfigInfo(unsigned Offset, bool IsActive)
658+
: Offset(Offset), IsActive(IsActive) {}
659+
};
660+
661+
struct ActiveRegionsInfo {
662+
ArrayRef<IfConfigInfo> Configs;
663+
};
664+
651665
/// Filled out by LangSupport::findInterfaceDocument().
652666
struct InterfaceDocInfo {
653667
/// Non-empty if a generated interface editor document has previously been
@@ -999,6 +1013,12 @@ class LangSupport {
9991013
std::function<void(const RequestResult<RelatedIdentsInfo> &)>
10001014
Receiver) = 0;
10011015

1016+
virtual void findActiveRegionsInFile(
1017+
StringRef Filename, ArrayRef<const char *> Args,
1018+
SourceKitCancellationToken CancellationToken,
1019+
std::function<void(const RequestResult<ActiveRegionsInfo> &)>
1020+
Receiver) = 0;
1021+
10021022
virtual llvm::Optional<std::pair<unsigned, unsigned>>
10031023
findUSRRange(StringRef DocumentName, StringRef USR) = 0;
10041024

Diff for: tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

+6
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,12 @@ class SwiftLangSupport : public LangSupport {
673673
std::function<void(const RequestResult<RelatedIdentsInfo> &)> Receiver)
674674
override;
675675

676+
void findActiveRegionsInFile(
677+
StringRef Filename, ArrayRef<const char *> Args,
678+
SourceKitCancellationToken CancellationToken,
679+
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver)
680+
override;
681+
676682
void syntacticRename(llvm::MemoryBuffer *InputBuf,
677683
ArrayRef<RenameLocations> RenameLocations,
678684
ArrayRef<const char*> Args,

Diff for: tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -2566,6 +2566,101 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
25662566
llvm::vfs::getRealFileSystem());
25672567
}
25682568

2569+
//===----------------------------------------------------------------------===//
2570+
// SwiftLangSupport::findActiveRegionsInFile
2571+
//===----------------------------------------------------------------------===//
2572+
2573+
namespace {
2574+
class IfConfigScanner : public SourceEntityWalker {
2575+
SmallVectorImpl<IfConfigInfo> &Infos;
2576+
SourceManager &SourceMgr;
2577+
unsigned BufferID = -1;
2578+
bool Cancelled = false;
2579+
2580+
public:
2581+
explicit IfConfigScanner(SourceFile &SrcFile, unsigned BufferID,
2582+
SmallVectorImpl<IfConfigInfo> &Infos)
2583+
: Infos(Infos), SourceMgr(SrcFile.getASTContext().SourceMgr),
2584+
BufferID(BufferID) {}
2585+
2586+
private:
2587+
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
2588+
if (Cancelled)
2589+
return false;
2590+
2591+
if (auto *IfDecl = dyn_cast<IfConfigDecl>(D)) {
2592+
for (auto &Clause : IfDecl->getClauses()) {
2593+
unsigned Offset = SourceMgr.getLocOffsetInBuffer(Clause.Loc, BufferID);
2594+
Infos.emplace_back(Offset, Clause.isActive);
2595+
}
2596+
}
2597+
2598+
return true;
2599+
}
2600+
};
2601+
2602+
} // end anonymous namespace
2603+
2604+
void SwiftLangSupport::findActiveRegionsInFile(
2605+
StringRef InputFile, ArrayRef<const char *> Args,
2606+
SourceKitCancellationToken CancellationToken,
2607+
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver) {
2608+
2609+
std::string Error;
2610+
SwiftInvocationRef Invok =
2611+
ASTMgr->getTypecheckInvocation(Args, InputFile, Error);
2612+
if (!Invok) {
2613+
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
2614+
Receiver(RequestResult<ActiveRegionsInfo>::fromError(Error));
2615+
return;
2616+
}
2617+
2618+
class IfConfigConsumer : public SwiftASTConsumer {
2619+
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver;
2620+
SwiftInvocationRef Invok;
2621+
2622+
public:
2623+
IfConfigConsumer(
2624+
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver,
2625+
SwiftInvocationRef Invok)
2626+
: Receiver(std::move(Receiver)), Invok(Invok) {}
2627+
2628+
void handlePrimaryAST(ASTUnitRef AstUnit) override {
2629+
auto &SrcFile = AstUnit->getPrimarySourceFile();
2630+
SmallVector<IfConfigInfo> Configs;
2631+
auto BufferID = SrcFile.getBufferID();
2632+
if (!BufferID)
2633+
return;
2634+
IfConfigScanner Scanner(SrcFile, *BufferID, Configs);
2635+
Scanner.walk(SrcFile);
2636+
2637+
// Sort by offset so nested decls are reported
2638+
// in source order (not tree order).
2639+
llvm::sort(Configs,
2640+
[](const IfConfigInfo &LHS, const IfConfigInfo &RHS) -> bool {
2641+
return LHS.Offset < RHS.Offset;
2642+
});
2643+
ActiveRegionsInfo Info;
2644+
Info.Configs = Configs;
2645+
Receiver(RequestResult<ActiveRegionsInfo>::fromResult(Info));
2646+
}
2647+
2648+
void cancelled() override {
2649+
Receiver(RequestResult<ActiveRegionsInfo>::cancelled());
2650+
}
2651+
2652+
void failed(StringRef Error) override {
2653+
LOG_WARN_FUNC("inactive ranges failed: " << Error);
2654+
Receiver(RequestResult<ActiveRegionsInfo>::fromError(Error));
2655+
}
2656+
};
2657+
2658+
auto Consumer = std::make_shared<IfConfigConsumer>(Receiver, Invok);
2659+
ASTMgr->processASTAsync(Invok, std::move(Consumer),
2660+
/*OncePerASTToken=*/nullptr, CancellationToken,
2661+
llvm::vfs::getRealFileSystem());
2662+
}
2663+
25692664
//===----------------------------------------------------------------------===//
25702665
// SwiftLangSupport::semanticRefactoring
25712666
//===----------------------------------------------------------------------===//

Diff for: tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
120120
.Case("conformingmethods", SourceKitRequest::ConformingMethodList)
121121
.Case("cursor", SourceKitRequest::CursorInfo)
122122
.Case("related-idents", SourceKitRequest::RelatedIdents)
123+
.Case("active-regions", SourceKitRequest::ActiveRegions)
123124
.Case("syntax-map", SourceKitRequest::SyntaxMap)
124125
.Case("structure", SourceKitRequest::Structure)
125126
.Case("format", SourceKitRequest::Format)

Diff for: tools/SourceKit/tools/sourcekitd-test/TestOptions.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum class SourceKitRequest {
3535
CodeCompleteSetPopularAPI,
3636
TypeContextInfo,
3737
ConformingMethodList,
38+
ActiveRegions,
3839
CursorInfo,
3940
RangeInfo,
4041
RelatedIdents,

Diff for: tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ static void printSemanticInfo();
7676
static void printRelatedIdents(sourcekitd_variant_t Info, StringRef Filename,
7777
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
7878
llvm::raw_ostream &OS);
79+
static void printActiveRegions(sourcekitd_variant_t Info, StringRef Filename,
80+
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
81+
llvm::raw_ostream &OS);
7982
static void printFoundInterface(sourcekitd_variant_t Info,
8083
llvm::raw_ostream &OS);
8184
static void printFoundUSR(sourcekitd_variant_t Info,
@@ -879,6 +882,10 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) {
879882
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestRelatedIdents);
880883
sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
881884
break;
885+
886+
case SourceKitRequest::ActiveRegions:
887+
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestActiveRegions);
888+
break;
882889

883890
case SourceKitRequest::SyntaxMap:
884891
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
@@ -1339,6 +1346,10 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
13391346
printRelatedIdents(Info, SourceFile, Opts.VFSFiles, llvm::outs());
13401347
break;
13411348

1349+
case SourceKitRequest::ActiveRegions:
1350+
printActiveRegions(Info, SourceFile, Opts.VFSFiles, llvm::outs());
1351+
break;
1352+
13421353
case SourceKitRequest::CursorInfo:
13431354
printCursorInfo(Info, SourceFile, Opts.VFSFiles, llvm::outs());
13441355
break;
@@ -2352,6 +2363,22 @@ static void printRelatedIdents(sourcekitd_variant_t Info, StringRef Filename,
23522363
OS << "END RANGES\n";
23532364
}
23542365

2366+
static void printActiveRegions(sourcekitd_variant_t Info, StringRef Filename,
2367+
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
2368+
llvm::raw_ostream &OS) {
2369+
OS << "START IF CONFIGS\n";
2370+
sourcekitd_variant_t Res =
2371+
sourcekitd_variant_dictionary_get_value(Info, KeyResults);
2372+
for (unsigned i=0, e = sourcekitd_variant_array_get_count(Res); i != e; ++i) {
2373+
sourcekitd_variant_t IfConfig = sourcekitd_variant_array_get_value(Res, i);
2374+
int64_t Offset = sourcekitd_variant_dictionary_get_int64(IfConfig, KeyOffset);
2375+
auto LineCol = resolveToLineCol(Offset, Filename, VFSFiles);
2376+
bool IsActive = sourcekitd_variant_dictionary_get_bool(IfConfig, KeyIsActive);
2377+
OS << LineCol.first << ':' << LineCol.second << " - " << (IsActive ? "active" : "inactive") << '\n';
2378+
}
2379+
OS << "END IF CONFIGS\n";
2380+
}
2381+
23552382
static void prepareDemangleRequest(sourcekitd_object_t Req,
23562383
const TestOptions &Opts) {
23572384
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestDemangle);

Diff for: tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ static void findRelatedIdents(StringRef Filename, int64_t Offset,
210210
SourceKitCancellationToken CancellationToken,
211211
ResponseReceiver Rec);
212212
213+
static void findActiveRegions(StringRef Filename, ArrayRef<const char *> Args,
214+
SourceKitCancellationToken CancellationToken,
215+
ResponseReceiver Rec);
216+
213217
static sourcekitd_response_t
214218
codeComplete(llvm::MemoryBuffer *InputBuf, int64_t Offset,
215219
Optional<RequestDict> optionsDict, ArrayRef<const char *> Args,
@@ -1682,6 +1686,25 @@ handleRequestRelatedIdents(const RequestDict &Req,
16821686
});
16831687
}
16841688
1689+
static void
1690+
handleRequestActiveRegions(const RequestDict &Req,
1691+
SourceKitCancellationToken CancellationToken,
1692+
ResponseReceiver Rec) {
1693+
if (checkVFSNotSupported(Req, Rec))
1694+
return;
1695+
1696+
handleSemanticRequest(Req, Rec, [Req, CancellationToken, Rec]() {
1697+
auto SourceFile = getSourceFileNameForRequestOrEmitError(Req, Rec);
1698+
if (!SourceFile)
1699+
return;
1700+
SmallVector<const char *> Args;
1701+
if (getCompilerArgumentsForRequestOrEmitError(Req, Args, Rec))
1702+
return;
1703+
1704+
return findActiveRegions(*SourceFile, Args, CancellationToken, Rec);
1705+
});
1706+
}
1707+
16851708
static void
16861709
handleRequestDiagnostics(const RequestDict &Req,
16871710
SourceKitCancellationToken CancellationToken,
@@ -1805,6 +1828,7 @@ void handleRequestImpl(sourcekitd_object_t ReqObj,
18051828
handleRequestFindLocalRenameRanges)
18061829
HANDLE_REQUEST(RequestNameTranslation, handleRequestNameTranslation)
18071830
HANDLE_REQUEST(RequestRelatedIdents, handleRequestRelatedIdents)
1831+
HANDLE_REQUEST(RequestActiveRegions, handleRequestActiveRegions)
18081832
HANDLE_REQUEST(RequestDiagnostics, handleRequestDiagnostics)
18091833

18101834
{
@@ -2576,6 +2600,38 @@ static void findRelatedIdents(StringRef Filename, int64_t Offset,
25762600
});
25772601
}
25782602

2603+
//===----------------------------------------------------------------------===//
2604+
// FindActiveRegions
2605+
//===----------------------------------------------------------------------===//
2606+
2607+
static void findActiveRegions(StringRef Filename, ArrayRef<const char *> Args,
2608+
SourceKitCancellationToken CancellationToken,
2609+
ResponseReceiver Rec) {
2610+
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
2611+
2612+
Lang.findActiveRegionsInFile(
2613+
Filename, Args, CancellationToken,
2614+
[Rec](const RequestResult<ActiveRegionsInfo> &Result) {
2615+
if (Result.isCancelled())
2616+
return Rec(createErrorRequestCancelled());
2617+
if (Result.isError())
2618+
return Rec(createErrorRequestFailed(Result.getError()));
2619+
2620+
const ActiveRegionsInfo &Info = Result.value();
2621+
2622+
ResponseBuilder RespBuilder;
2623+
auto Arr = RespBuilder.getDictionary().setArray(KeyResults);
2624+
for (auto Config : Info.Configs) {
2625+
auto Elem = Arr.appendDictionary();
2626+
Elem.set(KeyOffset, Config.Offset);
2627+
if (Config.IsActive)
2628+
Elem.setBool(KeyIsActive, true);
2629+
}
2630+
2631+
Rec(RespBuilder.createResponse());
2632+
});
2633+
}
2634+
25792635
//===----------------------------------------------------------------------===//
25802636
// CodeComplete
25812637
//===----------------------------------------------------------------------===//

Diff for: utils/gyb_sourcekit_support/UIDs.py

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(self, internal_name, external_name):
8383
KEY('BodyLength', 'key.bodylength'),
8484
KEY('DocOffset', 'key.docoffset'),
8585
KEY('DocLength', 'key.doclength'),
86+
KEY('IsActive', 'key.is_active'),
8687
KEY('IsLocal', 'key.is_local'),
8788
KEY('InheritedTypes', 'key.inheritedtypes'),
8889
KEY('Attributes', 'key.attributes'),
@@ -225,6 +226,7 @@ def __init__(self, internal_name, external_name):
225226
REQUEST('CodeCompleteSetCustom', 'source.request.codecomplete.setcustom'),
226227
REQUEST('TypeContextInfo', 'source.request.typecontextinfo'),
227228
REQUEST('ConformingMethodList', 'source.request.conformingmethods'),
229+
REQUEST('ActiveRegions', 'source.request.activeregions'),
228230
REQUEST('CursorInfo', 'source.request.cursorinfo'),
229231
REQUEST('RangeInfo', 'source.request.rangeinfo'),
230232
REQUEST('RelatedIdents', 'source.request.relatedidents'),

0 commit comments

Comments
 (0)