Skip to content

Commit 5601a98

Browse files
authored
Merge pull request swiftlang#22753 from nkcsgexi/request-type
SourceKit: Add a new request to collect expression types in a source file.
2 parents cb09c33 + 934104a commit 5601a98

File tree

10 files changed

+176
-2
lines changed

10 files changed

+176
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
func foo() { return 1 }
2+
3+
// RUN: %sourcekitd-test -req=collect-type %s -- %s | %FileCheck %s
4+
// CHECK: (20, 21): Int

tools/SourceKit/docs/Protocol.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,46 @@ Welcome to SourceKit. Type ':help' for assistance.
737737
}
738738
```
739739

740+
## Expression Type
741+
This request collects the types of all expressions in a source file after type checking.
742+
To fulfill this task, the client must provide the path to the Swift source file under
743+
type checking and the necessary compiler arguments to help resolve all dependencies.
740744

745+
### Request
746+
747+
```
748+
{
749+
<key.request>: (UID) <source.request.expression.type>,
750+
<key.sourcefile>: (string) // Absolute path to the file.
751+
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
752+
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
753+
// these must include the path to that file.
754+
}
755+
```
756+
757+
### Response
758+
```
759+
{
760+
<key.printedtypebuffer>: (string) // A text buffer where all expression types are printed to.
761+
<key.expression_type_list>: (array) [expr-type-info*] // A list of expression and type
762+
}
763+
```
764+
765+
```
766+
expr-type-info ::=
767+
{
768+
<key.expression_offset>: (int64) // Offset of an expression in the source file
769+
<key.expression_length>: (int64) // Length of an expression in the source file
770+
<key.type_offset>: (int64) // Offset of the printed type of the expression in the printed type buffer
771+
<key.type_length>: (int64) // Length of the printed type of the expression in the printed type buffer
772+
}
773+
```
774+
775+
### Testing
776+
777+
```
778+
$ sourcekitd-test -req=collect-type /path/to/file.swift -- /path/to/file.swift
779+
```
741780

742781
# UIDs
743782

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ struct CodeCompletionInfo {
123123
Optional<ArrayRef<ParameterStructure>> parametersStructure;
124124
};
125125

126+
struct ExpressionType {
127+
unsigned ExprOffset;
128+
unsigned ExprLength;
129+
unsigned TypeOffset;
130+
unsigned TypeLength;
131+
};
132+
133+
struct ExpressionTypesInFile {
134+
std::vector<ExpressionType> Results;
135+
StringRef TypeBuffer;
136+
};
137+
126138
class CodeCompletionConsumer {
127139
virtual void anchor();
128140

@@ -708,6 +720,10 @@ class LangSupport {
708720
ArrayRef<const char*> Args,
709721
CategorizedEditsReceiver Receiver) = 0;
710722

723+
virtual void collectExpressionTypes(StringRef FileName,
724+
ArrayRef<const char *> Args,
725+
std::function<void(const ExpressionTypesInFile&)> Receiver) = 0;
726+
711727
virtual void getDocInfo(llvm::MemoryBuffer *InputBuf,
712728
StringRef ModuleName,
713729
ArrayRef<const char *> Args,
@@ -726,7 +742,6 @@ class LangSupport {
726742

727743
virtual void getStatistics(StatisticsReceiver) = 0;
728744
};
729-
730745
} // namespace SourceKit
731746

732747
#endif

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ class SwiftLangSupport : public LangSupport {
521521
unsigned Length, ArrayRef<const char *> Args,
522522
CategorizedRenameRangesReceiver Receiver) override;
523523

524+
void collectExpressionTypes(StringRef FileName, ArrayRef<const char *> Args,
525+
std::function<void(const ExpressionTypesInFile&)> Receiver) override;
526+
524527
void semanticRefactoring(StringRef Filename, SemanticRefactoringInfo Info,
525528
ArrayRef<const char*> Args,
526529
CategorizedEditsReceiver Receiver) override;

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,3 +2032,49 @@ semanticRefactoring(StringRef Filename, SemanticRefactoringInfo Info,
20322032
static const char OncePerASTToken = 0;
20332033
getASTManager()->processASTAsync(Invok, std::move(Consumer), &OncePerASTToken);
20342034
}
2035+
2036+
void SwiftLangSupport::collectExpressionTypes(StringRef FileName,
2037+
ArrayRef<const char *> Args,
2038+
std::function<void(const ExpressionTypesInFile&)> Receiver) {
2039+
std::string Error;
2040+
SwiftInvocationRef Invok = ASTMgr->getInvocation(Args, FileName, Error);
2041+
if (!Invok) {
2042+
// FIXME: Report it as failed request.
2043+
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
2044+
Receiver({});
2045+
return;
2046+
}
2047+
assert(Invok);
2048+
class ExpressionTypeCollector: public SwiftASTConsumer {
2049+
std::function<void(const ExpressionTypesInFile&)> Receiver;
2050+
public:
2051+
ExpressionTypeCollector(std::function<void(const ExpressionTypesInFile&)> Receiver):
2052+
Receiver(std::move(Receiver)) {}
2053+
void handlePrimaryAST(ASTUnitRef AstUnit) override {
2054+
auto *SF = AstUnit->getCompilerInstance().getPrimarySourceFile();
2055+
std::vector<ExpressionTypeInfo> Scratch;
2056+
llvm::SmallString<256> TypeBuffer;
2057+
llvm::raw_svector_ostream OS(TypeBuffer);
2058+
ExpressionTypesInFile Result;
2059+
for (auto Item: collectExpressionType(*SF, Scratch, OS)) {
2060+
Result.Results.push_back({Item.offset, Item.length, Item.typeOffset,
2061+
Item.typeLength});
2062+
}
2063+
Result.TypeBuffer = OS.str();
2064+
Receiver(Result);
2065+
}
2066+
2067+
void cancelled() override {
2068+
Receiver({});
2069+
}
2070+
2071+
void failed(StringRef Error) override {
2072+
Receiver({});
2073+
}
2074+
};
2075+
auto Collector = std::make_shared<ExpressionTypeCollector>(Receiver);
2076+
/// FIXME: When request cancellation is implemented and Xcode adopts it,
2077+
/// don't use 'OncePerASTToken'.
2078+
static const char OncePerASTToken = 0;
2079+
getASTManager()->processASTAsync(Invok, std::move(Collector), &OncePerASTToken);
2080+
}

tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
152152
.Case("markup-xml", SourceKitRequest::MarkupToXML)
153153
.Case("stats", SourceKitRequest::Statistics)
154154
.Case("track-compiles", SourceKitRequest::EnableCompileNotifications)
155+
.Case("collect-type", SourceKitRequest::CollectExpresstionType)
155156
.Default(SourceKitRequest::None);
156157

157158
if (Request == SourceKitRequest::None) {
@@ -163,7 +164,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
163164
"doc-info/sema/interface-gen/interface-gen-openfind-usr/find-interface/"
164165
"open/close/edit/print-annotations/print-diags/extract-comment/module-groups/"
165166
"range/syntactic-rename/find-rename-ranges/translate/markup-xml/stats/"
166-
"track-compiles\n";
167+
"track-compiles/collect-type\n";
167168
return true;
168169
}
169170
break;

tools/SourceKit/tools/sourcekitd-test/TestOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum class SourceKitRequest {
6262
Statistics,
6363
SyntaxTree,
6464
EnableCompileNotifications,
65+
CollectExpresstionType,
6566
#define SEMANTIC_REFACTORING(KIND, NAME, ID) KIND,
6667
#include "swift/IDE/RefactoringKinds.def"
6768
};

tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static void printCursorInfo(sourcekitd_variant_t Info, StringRef Filename,
6868
static void printNameTranslationInfo(sourcekitd_variant_t Info, llvm::raw_ostream &OS);
6969
static void printRangeInfo(sourcekitd_variant_t Info, StringRef Filename,
7070
llvm::raw_ostream &OS);
71+
static void printExpressionType(sourcekitd_variant_t Info, llvm::raw_ostream &OS);
7172
static void printDocInfo(sourcekitd_variant_t Info, StringRef Filename);
7273
static void printInterfaceGen(sourcekitd_variant_t Info, bool CheckASCII);
7374
static void printSemanticInfo();
@@ -614,6 +615,11 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) {
614615
break;
615616
}
616617

618+
case SourceKitRequest::CollectExpresstionType: {
619+
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCollectExpressionType);
620+
break;
621+
}
622+
617623
#define SEMANTIC_REFACTORING(KIND, NAME, ID) case SourceKitRequest::KIND: \
618624
{ \
619625
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestSemanticRefactoring); \
@@ -1057,6 +1063,10 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
10571063
printRangeInfo(Info, SourceFile, llvm::outs());
10581064
break;
10591065

1066+
case SourceKitRequest::CollectExpresstionType:
1067+
printExpressionType(Info, llvm::outs());
1068+
break;
1069+
10601070
case SourceKitRequest::DocInfo:
10611071
printDocInfo(Info, SourceFile);
10621072
break;
@@ -1525,6 +1535,25 @@ static void printRangeInfo(sourcekitd_variant_t Info, StringRef FilenameIn,
15251535
if (Typename)
15261536
OS << "<type>" <<Typename << "</type>\n";
15271537
}
1538+
1539+
static void printExpressionType(sourcekitd_variant_t Info, llvm::raw_ostream &OS) {
1540+
auto *TypeBuffer = sourcekitd_variant_dictionary_get_string(Info, KeyTypeBuffer);
1541+
sourcekitd_variant_t ExprList = sourcekitd_variant_dictionary_get_value(Info,
1542+
KeyExpressionTypeList);
1543+
unsigned Count = sourcekitd_variant_array_get_count(ExprList);
1544+
for (unsigned i = 0; i != Count; ++i) {
1545+
sourcekitd_variant_t Item = sourcekitd_variant_array_get_value(ExprList, i);
1546+
unsigned Offset = sourcekitd_variant_dictionary_get_int64(Item, KeyExpressionOffset);
1547+
unsigned Length = sourcekitd_variant_dictionary_get_int64(Item, KeyExpressionLength);
1548+
StringRef PrintedType(TypeBuffer + sourcekitd_variant_dictionary_get_int64(Item,
1549+
KeyTypeOffset), sourcekitd_variant_dictionary_get_int64(Item, KeyTypeLength));
1550+
OS << "(" << Offset << ", " << Offset + Length << "): " << PrintedType << "\n";
1551+
}
1552+
if (!Count) {
1553+
OS << "cannot find expression types in the file\n";
1554+
}
1555+
}
1556+
15281557
static void printFoundInterface(sourcekitd_variant_t Info,
15291558
llvm::raw_ostream &OS) {
15301559
const char *Name = sourcekitd_variant_dictionary_get_string(Info,

tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ static sourcekitd_response_t reportDocInfo(llvm::MemoryBuffer *InputBuf,
141141

142142
static void reportCursorInfo(const CursorInfoData &Info, ResponseReceiver Rec);
143143

144+
static void reportExpressionTypeInfo(const ExpressionTypesInFile &Info, ResponseReceiver Rec);
145+
144146
static void reportRangeInfo(const RangeInfo &Info, ResponseReceiver Rec);
145147

146148
static void reportNameInfo(const NameTranslatingInfo &Info, ResponseReceiver Rec);
@@ -1000,6 +1002,14 @@ handleSemanticRequest(RequestDict Req,
10001002
return Rec(createErrorRequestInvalid("'key.line' or 'key.column' are required"));
10011003
}
10021004

1005+
if (ReqUID == RequestCollectExpressionType) {
1006+
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
1007+
return Lang.collectExpressionTypes(*SourceFile, Args,
1008+
[Rec](const ExpressionTypesInFile &Info) {
1009+
reportExpressionTypeInfo(Info, Rec);
1010+
});
1011+
}
1012+
10031013
if (ReqUID == RequestFindLocalRenameRanges) {
10041014
int64_t Line = 0, Column = 0, Length = 0;
10051015
if (Req.getInt64(KeyLine, Line, /*isOptional=*/false))
@@ -1723,6 +1733,25 @@ static void reportNameInfo(const NameTranslatingInfo &Info, ResponseReceiver Rec
17231733
Rec(RespBuilder.createResponse());
17241734
}
17251735

1736+
//===----------------------------------------------------------------------===//
1737+
// ReportExpressionTypeInfo
1738+
//===----------------------------------------------------------------------===//
1739+
static void reportExpressionTypeInfo(const ExpressionTypesInFile &Info,
1740+
ResponseReceiver Rec) {
1741+
ResponseBuilder Builder;
1742+
auto Dict = Builder.getDictionary();
1743+
Dict.set(KeyTypeBuffer, Info.TypeBuffer);
1744+
ResponseBuilder::Array Arr = Dict.setArray(KeyExpressionTypeList);
1745+
for (auto Result: Info.Results) {
1746+
auto Elem = Arr.appendDictionary();
1747+
Elem.set(KeyExpressionOffset, Result.ExprOffset);
1748+
Elem.set(KeyExpressionLength, Result.ExprLength);
1749+
Elem.set(KeyTypeOffset, Result.TypeOffset);
1750+
Elem.set(KeyTypeLength, Result.TypeLength);
1751+
}
1752+
Rec(Builder.createResponse());
1753+
}
1754+
17261755
//===----------------------------------------------------------------------===//
17271756
// FindRelatedIdents
17281757
//===----------------------------------------------------------------------===//

utils/gyb_sourcekit_support/UIDs.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ def __init__(self, internal_name, external_name):
163163
KEY('ImplicitMembers', 'key.implicitmembers'),
164164
KEY('ExpectedTypes', 'key.expectedtypes'),
165165
KEY('Members', 'key.members'),
166+
KEY('TypeBuffer', 'key.printedtypebuffer'),
167+
KEY('ExpressionTypeList', 'key.expression_type_list'),
168+
KEY('ExpressionOffset', 'key.expression_offset'),
169+
KEY('ExpressionLength', 'key.expression_length'),
170+
KEY('TypeOffset', 'key.type_offset'),
171+
KEY('TypeLength', 'key.type_length'),
166172
]
167173

168174

@@ -219,6 +225,7 @@ def __init__(self, internal_name, external_name):
219225
REQUEST('EnableCompileNotifications',
220226
'source.request.enable-compile-notifications'),
221227
REQUEST('TestNotification', 'source.request.test_notification'),
228+
REQUEST('CollectExpressionType', 'source.request.expression.type'),
222229
]
223230

224231

0 commit comments

Comments
 (0)