Merge pull request #63816 from apple/louisd/sourcekit-inactive-ranges-request

[SourceKit] Add "Active Regions" request
This commit is contained in:
Louis D'hauwe
2023-03-02 08:07:45 -08:00
committed by GitHub
11 changed files with 279 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
#if FLAG_1
class Foo {
#if FLAG_2
func debugOnly() {
}
#endif
}
#elseif FLAG_3
class GracefulFallback {
}
#else
class Fallback {
}
#endif
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
// CHECK1: START IF CONFIGS
// CHECK1-NEXT: 1:1 - active
// CHECK1-NEXT: 3:5 - inactive
// CHECK1-NEXT: 9:1 - inactive
// CHECK1-NEXT: 13:1 - inactive
// CHECK1-NEXT: END IF CONFIGS
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_2 -module-name active_regions %s | %FileCheck -check-prefix=CHECK2 %s
// CHECK2: START IF CONFIGS
// CHECK2-NEXT: 1:1 - inactive
// CHECK2-NEXT: 9:1 - inactive
// CHECK2-NEXT: 13:1 - active
// CHECK2-NEXT: END IF CONFIGS
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -D FLAG_2 -module-name active_regions %s | %FileCheck -check-prefix=CHECK3 %s
// CHECK3: START IF CONFIGS
// CHECK3-NEXT: 1:1 - active
// CHECK3-NEXT: 3:5 - active
// CHECK3-NEXT: 9:1 - inactive
// CHECK3-NEXT: 13:1 - inactive
// CHECK3-NEXT: END IF CONFIGS
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_3 -module-name active_regions %s | %FileCheck -check-prefix=CHECK4 %s
// CHECK4: START IF CONFIGS
// CHECK4-NEXT: 1:1 - inactive
// CHECK4-NEXT: 9:1 - active
// CHECK4-NEXT: 13:1 - inactive
// CHECK4-NEXT: END IF CONFIGS

View File

@@ -0,0 +1,12 @@
#if FOO > 10
class Foo {
}
#else
class Fallback {
}
#endif
// RUN: %sourcekitd-test -req=active-regions %s -- -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
// CHECK1: START IF CONFIGS
// CHECK1-NEXT: 1:1 - inactive
// CHECK1-NEXT: 4:1 - active
// CHECK1-NEXT: END IF CONFIGS

View File

@@ -0,0 +1,12 @@
#if FLAG_1
class Foo {
}
#else
class Fallback {
}
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
// CHECK1: START IF CONFIGS
// CHECK1-NEXT: 1:1 - active
// CHECK1-NEXT: 4:1 - inactive
// CHECK1-NEXT: END IF CONFIGS

View File

@@ -648,6 +648,20 @@ struct RelatedIdentsInfo {
ArrayRef<std::pair<unsigned, unsigned>> Ranges;
};
/// Represent one branch of an if config.
/// Either `#if`, `#else` or `#elseif`.
struct IfConfigInfo {
unsigned Offset;
bool IsActive;
IfConfigInfo(unsigned Offset, bool IsActive)
: Offset(Offset), IsActive(IsActive) {}
};
struct ActiveRegionsInfo {
ArrayRef<IfConfigInfo> Configs;
};
/// Filled out by LangSupport::findInterfaceDocument().
struct InterfaceDocInfo {
/// Non-empty if a generated interface editor document has previously been
@@ -999,6 +1013,12 @@ public:
std::function<void(const RequestResult<RelatedIdentsInfo> &)>
Receiver) = 0;
virtual void findActiveRegionsInFile(
StringRef Filename, ArrayRef<const char *> Args,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ActiveRegionsInfo> &)>
Receiver) = 0;
virtual llvm::Optional<std::pair<unsigned, unsigned>>
findUSRRange(StringRef DocumentName, StringRef USR) = 0;

View File

@@ -673,6 +673,12 @@ public:
std::function<void(const RequestResult<RelatedIdentsInfo> &)> Receiver)
override;
void findActiveRegionsInFile(
StringRef Filename, ArrayRef<const char *> Args,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver)
override;
void syntacticRename(llvm::MemoryBuffer *InputBuf,
ArrayRef<RenameLocations> RenameLocations,
ArrayRef<const char*> Args,

View File

@@ -2566,6 +2566,101 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
llvm::vfs::getRealFileSystem());
}
//===----------------------------------------------------------------------===//
// SwiftLangSupport::findActiveRegionsInFile
//===----------------------------------------------------------------------===//
namespace {
class IfConfigScanner : public SourceEntityWalker {
SmallVectorImpl<IfConfigInfo> &Infos;
SourceManager &SourceMgr;
unsigned BufferID = -1;
bool Cancelled = false;
public:
explicit IfConfigScanner(SourceFile &SrcFile, unsigned BufferID,
SmallVectorImpl<IfConfigInfo> &Infos)
: Infos(Infos), SourceMgr(SrcFile.getASTContext().SourceMgr),
BufferID(BufferID) {}
private:
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
if (Cancelled)
return false;
if (auto *IfDecl = dyn_cast<IfConfigDecl>(D)) {
for (auto &Clause : IfDecl->getClauses()) {
unsigned Offset = SourceMgr.getLocOffsetInBuffer(Clause.Loc, BufferID);
Infos.emplace_back(Offset, Clause.isActive);
}
}
return true;
}
};
} // end anonymous namespace
void SwiftLangSupport::findActiveRegionsInFile(
StringRef InputFile, ArrayRef<const char *> Args,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver) {
std::string Error;
SwiftInvocationRef Invok =
ASTMgr->getTypecheckInvocation(Args, InputFile, Error);
if (!Invok) {
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
Receiver(RequestResult<ActiveRegionsInfo>::fromError(Error));
return;
}
class IfConfigConsumer : public SwiftASTConsumer {
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver;
SwiftInvocationRef Invok;
public:
IfConfigConsumer(
std::function<void(const RequestResult<ActiveRegionsInfo> &)> Receiver,
SwiftInvocationRef Invok)
: Receiver(std::move(Receiver)), Invok(Invok) {}
void handlePrimaryAST(ASTUnitRef AstUnit) override {
auto &SrcFile = AstUnit->getPrimarySourceFile();
SmallVector<IfConfigInfo> Configs;
auto BufferID = SrcFile.getBufferID();
if (!BufferID)
return;
IfConfigScanner Scanner(SrcFile, *BufferID, Configs);
Scanner.walk(SrcFile);
// Sort by offset so nested decls are reported
// in source order (not tree order).
llvm::sort(Configs,
[](const IfConfigInfo &LHS, const IfConfigInfo &RHS) -> bool {
return LHS.Offset < RHS.Offset;
});
ActiveRegionsInfo Info;
Info.Configs = Configs;
Receiver(RequestResult<ActiveRegionsInfo>::fromResult(Info));
}
void cancelled() override {
Receiver(RequestResult<ActiveRegionsInfo>::cancelled());
}
void failed(StringRef Error) override {
LOG_WARN_FUNC("inactive ranges failed: " << Error);
Receiver(RequestResult<ActiveRegionsInfo>::fromError(Error));
}
};
auto Consumer = std::make_shared<IfConfigConsumer>(Receiver, Invok);
ASTMgr->processASTAsync(Invok, std::move(Consumer),
/*OncePerASTToken=*/nullptr, CancellationToken,
llvm::vfs::getRealFileSystem());
}
//===----------------------------------------------------------------------===//
// SwiftLangSupport::semanticRefactoring
//===----------------------------------------------------------------------===//

View File

@@ -120,6 +120,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
.Case("conformingmethods", SourceKitRequest::ConformingMethodList)
.Case("cursor", SourceKitRequest::CursorInfo)
.Case("related-idents", SourceKitRequest::RelatedIdents)
.Case("active-regions", SourceKitRequest::ActiveRegions)
.Case("syntax-map", SourceKitRequest::SyntaxMap)
.Case("structure", SourceKitRequest::Structure)
.Case("format", SourceKitRequest::Format)

View File

@@ -35,6 +35,7 @@ enum class SourceKitRequest {
CodeCompleteSetPopularAPI,
TypeContextInfo,
ConformingMethodList,
ActiveRegions,
CursorInfo,
RangeInfo,
RelatedIdents,

View File

@@ -76,6 +76,9 @@ static void printSemanticInfo();
static void printRelatedIdents(sourcekitd_variant_t Info, StringRef Filename,
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
llvm::raw_ostream &OS);
static void printActiveRegions(sourcekitd_variant_t Info, StringRef Filename,
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
llvm::raw_ostream &OS);
static void printFoundInterface(sourcekitd_variant_t Info,
llvm::raw_ostream &OS);
static void printFoundUSR(sourcekitd_variant_t Info,
@@ -880,6 +883,10 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) {
sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
break;
case SourceKitRequest::ActiveRegions:
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestActiveRegions);
break;
case SourceKitRequest::SyntaxMap:
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen);
sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str());
@@ -1339,6 +1346,10 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
printRelatedIdents(Info, SourceFile, Opts.VFSFiles, llvm::outs());
break;
case SourceKitRequest::ActiveRegions:
printActiveRegions(Info, SourceFile, Opts.VFSFiles, llvm::outs());
break;
case SourceKitRequest::CursorInfo:
printCursorInfo(Info, SourceFile, Opts.VFSFiles, llvm::outs());
break;
@@ -2352,6 +2363,22 @@ static void printRelatedIdents(sourcekitd_variant_t Info, StringRef Filename,
OS << "END RANGES\n";
}
static void printActiveRegions(sourcekitd_variant_t Info, StringRef Filename,
const llvm::StringMap<TestOptions::VFSFile> &VFSFiles,
llvm::raw_ostream &OS) {
OS << "START IF CONFIGS\n";
sourcekitd_variant_t Res =
sourcekitd_variant_dictionary_get_value(Info, KeyResults);
for (unsigned i=0, e = sourcekitd_variant_array_get_count(Res); i != e; ++i) {
sourcekitd_variant_t IfConfig = sourcekitd_variant_array_get_value(Res, i);
int64_t Offset = sourcekitd_variant_dictionary_get_int64(IfConfig, KeyOffset);
auto LineCol = resolveToLineCol(Offset, Filename, VFSFiles);
bool IsActive = sourcekitd_variant_dictionary_get_bool(IfConfig, KeyIsActive);
OS << LineCol.first << ':' << LineCol.second << " - " << (IsActive ? "active" : "inactive") << '\n';
}
OS << "END IF CONFIGS\n";
}
static void prepareDemangleRequest(sourcekitd_object_t Req,
const TestOptions &Opts) {
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestDemangle);

View File

@@ -210,6 +210,10 @@ static void findRelatedIdents(StringRef Filename, int64_t Offset,
SourceKitCancellationToken CancellationToken,
ResponseReceiver Rec);
static void findActiveRegions(StringRef Filename, ArrayRef<const char *> Args,
SourceKitCancellationToken CancellationToken,
ResponseReceiver Rec);
static sourcekitd_response_t
codeComplete(llvm::MemoryBuffer *InputBuf, int64_t Offset,
Optional<RequestDict> optionsDict, ArrayRef<const char *> Args,
@@ -1682,6 +1686,25 @@ handleRequestRelatedIdents(const RequestDict &Req,
});
}
static void
handleRequestActiveRegions(const RequestDict &Req,
SourceKitCancellationToken CancellationToken,
ResponseReceiver Rec) {
if (checkVFSNotSupported(Req, Rec))
return;
handleSemanticRequest(Req, Rec, [Req, CancellationToken, Rec]() {
auto SourceFile = getSourceFileNameForRequestOrEmitError(Req, Rec);
if (!SourceFile)
return;
SmallVector<const char *> Args;
if (getCompilerArgumentsForRequestOrEmitError(Req, Args, Rec))
return;
return findActiveRegions(*SourceFile, Args, CancellationToken, Rec);
});
}
static void
handleRequestDiagnostics(const RequestDict &Req,
SourceKitCancellationToken CancellationToken,
@@ -1805,6 +1828,7 @@ void handleRequestImpl(sourcekitd_object_t ReqObj,
handleRequestFindLocalRenameRanges)
HANDLE_REQUEST(RequestNameTranslation, handleRequestNameTranslation)
HANDLE_REQUEST(RequestRelatedIdents, handleRequestRelatedIdents)
HANDLE_REQUEST(RequestActiveRegions, handleRequestActiveRegions)
HANDLE_REQUEST(RequestDiagnostics, handleRequestDiagnostics)
{
@@ -2576,6 +2600,38 @@ static void findRelatedIdents(StringRef Filename, int64_t Offset,
});
}
//===----------------------------------------------------------------------===//
// FindActiveRegions
//===----------------------------------------------------------------------===//
static void findActiveRegions(StringRef Filename, ArrayRef<const char *> Args,
SourceKitCancellationToken CancellationToken,
ResponseReceiver Rec) {
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
Lang.findActiveRegionsInFile(
Filename, Args, CancellationToken,
[Rec](const RequestResult<ActiveRegionsInfo> &Result) {
if (Result.isCancelled())
return Rec(createErrorRequestCancelled());
if (Result.isError())
return Rec(createErrorRequestFailed(Result.getError()));
const ActiveRegionsInfo &Info = Result.value();
ResponseBuilder RespBuilder;
auto Arr = RespBuilder.getDictionary().setArray(KeyResults);
for (auto Config : Info.Configs) {
auto Elem = Arr.appendDictionary();
Elem.set(KeyOffset, Config.Offset);
if (Config.IsActive)
Elem.setBool(KeyIsActive, true);
}
Rec(RespBuilder.createResponse());
});
}
//===----------------------------------------------------------------------===//
// CodeComplete
//===----------------------------------------------------------------------===//

View File

@@ -83,6 +83,7 @@ UID_KEYS = [
KEY('BodyLength', 'key.bodylength'),
KEY('DocOffset', 'key.docoffset'),
KEY('DocLength', 'key.doclength'),
KEY('IsActive', 'key.is_active'),
KEY('IsLocal', 'key.is_local'),
KEY('InheritedTypes', 'key.inheritedtypes'),
KEY('Attributes', 'key.attributes'),
@@ -225,6 +226,7 @@ UID_REQUESTS = [
REQUEST('CodeCompleteSetCustom', 'source.request.codecomplete.setcustom'),
REQUEST('TypeContextInfo', 'source.request.typecontextinfo'),
REQUEST('ConformingMethodList', 'source.request.conformingmethods'),
REQUEST('ActiveRegions', 'source.request.activeregions'),
REQUEST('CursorInfo', 'source.request.cursorinfo'),
REQUEST('RangeInfo', 'source.request.rangeinfo'),
REQUEST('RelatedIdents', 'source.request.relatedidents'),