Skip to content

Commit 74e86a8

Browse files
committed
SourceKit: Add a new request to collect expression types in a source file.
This request collects the types of all expressions in a source file after type checking. To fulfill this task, the client must provide the path to the Swift source file under type checking and the necessary compiler arguments to help resolve all dependencies. Request: { <key.request>: (UID) <source.request.expression.type>, <key.sourcefile>: (string) // Absolute path to the file. <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. } Response: { <key.printedtypebuffer>: (string) // A text buffer where all expression types are printed to. <key.expression_type_list>: (array) [expr-type-info*] // A list of expression and type } expr-type-info ::= { <key.expression_offset>: (int64) // Offset of an expression in the source file <key.expression_length>: (int64) // Length of an expression in the source file <key.type_offset>: (int64) // Offset of the printed type of the expression in the printed type buffer <key.type_length>: (int64) // Length of the printed type of the expression in the printed type buffer } rdar:://35199889
1 parent b52472b commit 74e86a8

File tree

9 files changed

+137
-2
lines changed

9 files changed

+137
-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/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)