Skip to content

Commit 2a86010

Browse files
authored
[SourceKit] Implement a new SourceKit request to generate the interface for a given type. rdar://27306890 (#3586)
This patch allows SourceKit to generate the interface for a given type specified by its mangled name. Type interface is refined decl printing with type parameters localized and unusable members hidden. Required field: "key.request": "source.request.editor.open.interface.swifttype" "key.usr": the mangled name of the given type.
1 parent 53a3a65 commit 2a86010

File tree

10 files changed

+245
-23
lines changed

10 files changed

+245
-23
lines changed

include/swift/IDE/ModuleInterfacePrinting.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ Optional<StringRef>
4949
findGroupNameForUSR(ModuleDecl *M, StringRef USR);
5050

5151
bool printTypeInterface(ModuleDecl *M, Type Ty, ASTPrinter &Printer,
52-
std::string &Error);
52+
std::string &TypeName, std::string &Error);
5353

5454
bool printTypeInterface(ModuleDecl *M, StringRef TypeUSR, ASTPrinter &Printer,
55-
std::string &Error);
55+
std::string &TyepName, std::string &Error);
5656

5757
void printModuleInterface(ModuleDecl *M, Optional<StringRef> Group,
5858
ModuleTraversalOptions TraversalOptions,

lib/IDE/ModuleInterfacePrinting.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,38 @@ getUnderlyingClangModuleForImport(ImportDecl *Import) {
147147
return nullptr;
148148
}
149149

150+
static void printTypeNameToString(Type Ty, std::string &Text) {
151+
SmallString<128> Buffer;
152+
llvm::raw_svector_ostream OS(Buffer);
153+
Ty->print(OS);
154+
Text = OS.str();
155+
}
156+
150157
bool swift::ide::
151158
printTypeInterface(ModuleDecl *M, Type Ty, ASTPrinter &Printer,
152-
std::string &Error) {
153-
if (!Ty)
154-
return false;
159+
std::string &TypeName, std::string &Error) {
160+
if (!Ty) {
161+
if (Error.empty())
162+
Error = "type cannot be null.";
163+
return true;
164+
}
155165
Ty = Ty->getRValueType();
156166
if (auto ND = Ty->getNominalOrBoundGenericNominal()) {
157167
PrintOptions Options = PrintOptions::printTypeInterface(Ty.getPointer(), M);
158168
ND->print(Printer, Options);
159-
return true;
169+
printTypeNameToString(Ty, TypeName);
170+
return false;
160171
}
161172
Error = "cannot find declaration of type.";
162-
return false;
173+
return true;
163174
}
164175

165176
bool swift::ide::
166177
printTypeInterface(ModuleDecl *M, StringRef TypeUSR, ASTPrinter &Printer,
167-
std::string &Error) {
178+
std::string &TypeName, std::string &Error) {
168179
return printTypeInterface(M, getTypeFromMangledSymbolname(M->getASTContext(),
169180
TypeUSR, Error),
170-
Printer, Error);
181+
Printer, TypeName, Error);
171182
}
172183

173184
void swift::ide::printModuleInterface(Module *M, Optional<StringRef> Group,
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtGSaSi_ %s -- %s | FileCheck -check-prefix=CHECK1 %s
2+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtGSaSS_ %s -- %s | FileCheck -check-prefix=CHECK2 %s
3+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtV14gen_swift_type1A %s -- %s | FileCheck -check-prefix=CHECK3 %s
4+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtGSaV14gen_swift_type1A_ %s -- %s | FileCheck -check-prefix=CHECK4 %s
5+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtGC14gen_swift_type1DCS_2T1_ %s -- %s | FileCheck -check-prefix=CHECK5 %s
6+
// RUN: %sourcekitd-test -req=interface-gen -usr _TtGC14gen_swift_type1DSi_ %s -- %s | FileCheck -check-prefix=CHECK6 %s
7+
8+
public struct A {
9+
public func fa() {}
10+
}
11+
extension A {
12+
public func fea1() {}
13+
}
14+
extension A {
15+
public func fea2() {}
16+
}
17+
18+
class C1 {
19+
func f1() {
20+
var abcd : A
21+
abcd.fa()
22+
var intarr : [Int]
23+
intarr.append(1)
24+
}
25+
}
26+
27+
struct S1 {
28+
func f1(a : [A]) {
29+
_ = a.count
30+
}
31+
}
32+
// CHECK1: public struct Array<Int> : RandomAccessCollection, MutableCollection {
33+
34+
// CHECK2: public struct Array<String> : RandomAccessCollection, MutableCollection {
35+
36+
// CHECK3: public struct A
37+
// CHECK3: public func fa()
38+
// CHECK3: public func fea1()
39+
// CHECK3: public func fea2()
40+
41+
// CHECK4: public struct Array<A> : RandomAccessCollection, MutableCollection {
42+
43+
public protocol P1 { }
44+
public class T1 : P1 { }
45+
public class D<T> { public func foo() {}}
46+
47+
class C2 {
48+
func f() {
49+
let D1 = D<T1>()
50+
let D2 = D<Int>()
51+
D1.foo()
52+
D2.foo()
53+
}
54+
}
55+
56+
extension D where T : P1 {
57+
public func conditionalFunc1() {}
58+
public func conditionalFunc2(t : T) -> T {return t}
59+
}
60+
61+
extension D {
62+
public func unconditionalFunc1(){}
63+
public func unconditionalFunc2(t : T) -> T {return t}
64+
}
65+
66+
// CHECK5: public class D<T1> {
67+
// CHECK5: public func foo()
68+
// CHECK5: public func conditionalFunc1()
69+
// CHECK5: public func conditionalFunc2(t: T1) -> T1
70+
// CHECK5: public func unconditionalFunc1()
71+
// CHECK5: public func unconditionalFunc2(t: T1) -> T1
72+
73+
// CHECK6: public class D<Int> {
74+
// CHECK6: public func foo()
75+
// CHECK6: public func unconditionalFunc1()
76+
// CHECK6: public func unconditionalFunc2(t: Int) -> Int

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,10 @@ class LangSupport {
413413
bool SynthesizedExtensions,
414414
Optional<StringRef> InterestedUSR) = 0;
415415

416+
virtual void editorOpenTypeInterface(EditorConsumer &Consumer,
417+
ArrayRef<const char *> Args,
418+
StringRef TypeUSR) = 0;
419+
416420
virtual void editorOpenHeaderInterface(EditorConsumer &Consumer,
417421
StringRef Name,
418422
StringRef HeaderName,

tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,53 @@ SwiftInterfaceGenContext::create(StringRef DocumentName,
442442
return IFaceGenCtx;
443443
}
444444

445+
SwiftInterfaceGenContextRef
446+
SwiftInterfaceGenContext::createForTypeInterface(CompilerInvocation Invocation,
447+
StringRef TypeUSR,
448+
std::string &ErrorMsg) {
449+
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
450+
IFaceGenCtx->Impl.IsModule = false;
451+
IFaceGenCtx->Impl.ModuleOrHeaderName = TypeUSR;
452+
IFaceGenCtx->Impl.Invocation = Invocation;
453+
CompilerInstance &CI = IFaceGenCtx->Impl.Instance;
454+
SourceTextInfo &Info = IFaceGenCtx->Impl.Info;
455+
456+
// Display diagnostics to stderr.
457+
CI.addDiagnosticConsumer(&IFaceGenCtx->Impl.DiagConsumer);
458+
459+
if (CI.setup(Invocation)) {
460+
ErrorMsg = "Error during invocation setup";
461+
return nullptr;
462+
}
463+
CI.performSema();
464+
ASTContext &Ctx = CI.getASTContext();
465+
CloseClangModuleFiles scopedCloseFiles(*Ctx.getClangModuleLoader());
466+
467+
// Load standard library so that Clang importer can use it.
468+
auto *Stdlib = getModuleByFullName(Ctx, Ctx.StdlibModuleName);
469+
if (!Stdlib) {
470+
ErrorMsg = "Could not load the stdlib module";
471+
return nullptr;
472+
}
473+
auto *Module = CI.getMainModule();
474+
if (!Module) {
475+
ErrorMsg = "Could not load the main module";
476+
return nullptr;
477+
}
478+
SmallString<128> Text;
479+
llvm::raw_svector_ostream OS(Text);
480+
AnnotatingPrinter Printer(Info, OS);
481+
if (ide::printTypeInterface(Module, TypeUSR, Printer,
482+
IFaceGenCtx->Impl.DocumentName, ErrorMsg))
483+
return nullptr;
484+
IFaceGenCtx->Impl.Info.Text = OS.str();
485+
if (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx->Impl.Info.Text)) {
486+
ErrorMsg = "Error during syntactic parsing";
487+
return nullptr;
488+
}
489+
return IFaceGenCtx;
490+
}
491+
445492
SwiftInterfaceGenContext::SwiftInterfaceGenContext()
446493
: Impl(*new Implementation) {
447494
}
@@ -593,11 +640,45 @@ SwiftInterfaceGenMap::find(StringRef ModuleName,
593640
}
594641
return nullptr;
595642
}
643+
//===----------------------------------------------------------------------===//
644+
// EditorOpenTypeInterface
645+
//===----------------------------------------------------------------------===//
646+
void SwiftLangSupport::editorOpenTypeInterface(EditorConsumer &Consumer,
647+
ArrayRef<const char *> Args,
648+
StringRef TypeUSR) {
649+
CompilerInstance CI;
650+
// Display diagnostics to stderr.
651+
PrintingDiagnosticConsumer PrintDiags;
652+
CI.addDiagnosticConsumer(&PrintDiags);
653+
654+
CompilerInvocation Invocation;
655+
std::string Error;
656+
if (getASTManager().initCompilerInvocation(Invocation, Args, CI.getDiags(),
657+
StringRef(), Error)) {
658+
Consumer.handleRequestError(Error.c_str());
659+
return;
660+
}
661+
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
662+
663+
std::string ErrMsg;
664+
auto IFaceGenRef = SwiftInterfaceGenContext::createForTypeInterface(
665+
Invocation,
666+
TypeUSR,
667+
ErrMsg);
668+
if (!IFaceGenRef) {
669+
Consumer.handleRequestError(ErrMsg.c_str());
670+
return;
671+
}
672+
673+
IFaceGenRef->reportEditorInfo(Consumer);
674+
// reportEditorInfo requires exclusive access to the AST, so don't add this
675+
// to the service cache until it has returned.
676+
IFaceGenContexts.set(TypeUSR, IFaceGenRef);
677+
}
596678

597679
//===----------------------------------------------------------------------===//
598680
// EditorOpenInterface
599681
//===----------------------------------------------------------------------===//
600-
601682
void SwiftLangSupport::editorOpenInterface(EditorConsumer &Consumer,
602683
StringRef Name,
603684
StringRef ModuleName,

tools/SourceKit/lib/SwiftLang/SwiftInterfaceGenContext.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class SwiftInterfaceGenContext :
4242
bool SynthesizedExtensions,
4343
Optional<StringRef> InterestedUSR);
4444

45+
static SwiftInterfaceGenContextRef
46+
createForTypeInterface(swift::CompilerInvocation Invocation,
47+
StringRef TypeUSR,
48+
std::string &ErrorMsg);
49+
4550
static SwiftInterfaceGenContextRef createForSwiftSource(StringRef DocumentName,
4651
StringRef SourceFileName,
4752
ASTUnitRef AstUnit,

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,10 @@ class SwiftLangSupport : public LangSupport {
340340
bool SynthesizedExtensions,
341341
Optional<StringRef> InterestedUSR) override;
342342

343+
void editorOpenTypeInterface(EditorConsumer &Consumer,
344+
ArrayRef<const char *> Args,
345+
StringRef TypeUSR) override;
346+
343347
void editorOpenHeaderInterface(EditorConsumer &Consumer,
344348
StringRef Name,
345349
StringRef HeaderName,

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ static sourcekitd_uid_t RequestRelatedIdents;
142142
static sourcekitd_uid_t RequestEditorOpen;
143143
static sourcekitd_uid_t RequestEditorOpenInterface;
144144
static sourcekitd_uid_t RequestEditorOpenSwiftSourceInterface;
145+
static sourcekitd_uid_t RequestEditorOpenSwiftTypeInterface;
145146
static sourcekitd_uid_t RequestEditorOpenHeaderInterface;
146147
static sourcekitd_uid_t RequestEditorExtractTextFromComment;
147148
static sourcekitd_uid_t RequestEditorReplaceText;
@@ -258,6 +259,7 @@ static int skt_main(int argc, const char **argv) {
258259
RequestEditorOpen = sourcekitd_uid_get_from_cstr("source.request.editor.open");
259260
RequestEditorOpenInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface");
260261
RequestEditorOpenSwiftSourceInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.swiftsource");
262+
RequestEditorOpenSwiftTypeInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.swifttype");
261263
RequestEditorOpenHeaderInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.header");
262264
RequestEditorExtractTextFromComment = sourcekitd_uid_get_from_cstr("source.request.editor.extract.comment");
263265
RequestEditorReplaceText = sourcekitd_uid_get_from_cstr("source.request.editor.replacetext");
@@ -615,27 +617,35 @@ static int handleTestInvocation(ArrayRef<const char *> Args,
615617
case SourceKitRequest::InterfaceGenOpen:
616618
sourcekitd_request_dictionary_set_int64(Req, KeySynthesizedExtension,
617619
Opts.SynthesizedExtensions);
618-
if (Opts.ModuleName.empty() && Opts.HeaderPath.empty() && Opts.SourceFile.empty()) {
619-
llvm::errs() << "Missing '-module <module name>' or '-header <path>' or '<source-file>' \n";
620+
if (Opts.ModuleName.empty() && Opts.HeaderPath.empty() &&
621+
Opts.SourceFile.empty() && Opts.USR.empty()) {
622+
llvm::errs() << "Missing '-module <module name>' or '-header <path>'" <<
623+
"or '<source-file>' or '-usr <USR>' \n";
620624
return 1;
621625
}
622626
if (!Opts.ModuleName.empty()) {
623627
sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
624628
RequestEditorOpenInterface);
625-
} else if (Opts.SourceFile.empty()){
629+
} else if (!Opts.USR.empty()) {
626630
sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
627-
RequestEditorOpenHeaderInterface);
628-
} else {
631+
RequestEditorOpenSwiftTypeInterface);
632+
} else if (!Opts.SourceFile.empty()) {
629633
sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
630634
RequestEditorOpenSwiftSourceInterface);
635+
} else {
636+
sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
637+
RequestEditorOpenHeaderInterface);
631638
}
639+
632640
sourcekitd_request_dictionary_set_string(Req, KeyName, getInterfaceGenDocumentName());
633641
if (!Opts.ModuleGroupName.empty())
634642
sourcekitd_request_dictionary_set_string(Req, KeyGroupName,
635643
Opts.ModuleGroupName.c_str());
636644
if (!Opts.InterestedUSR.empty())
637645
sourcekitd_request_dictionary_set_string(Req, KeyInterestedUSR,
638646
Opts.InterestedUSR.c_str());
647+
if (!Opts.USR.empty())
648+
sourcekitd_request_dictionary_set_string(Req, KeyUSR, Opts.USR.c_str());
639649
break;
640650

641651
case SourceKitRequest::FindInterfaceDoc:

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ static LazySKDUID RequestEditorOpenHeaderInterface(
8888
"source.request.editor.open.interface.header");
8989
static LazySKDUID RequestEditorOpenSwiftSourceInterface(
9090
"source.request.editor.open.interface.swiftsource");
91+
static LazySKDUID RequestEditorOpenSwiftTypeInterface(
92+
"source.request.editor.open.interface.swifttype");
9193
static LazySKDUID RequestEditorExtractTextFromComment(
9294
"source.request.editor.extract.comment");
9395
static LazySKDUID RequestEditorClose("source.request.editor.close");
@@ -206,6 +208,10 @@ editorOpenSwiftSourceInterface(StringRef Name, StringRef SourceName,
206208
ArrayRef<const char *> Args,
207209
ResponseReceiver Rec);
208210

211+
static void
212+
editorOpenSwiftTypeInterface(StringRef TypeUsr, ArrayRef<const char *> Args,
213+
ResponseReceiver Rec);
214+
209215
static sourcekitd_response_t editorExtractTextFromComment(StringRef Source);
210216

211217
static sourcekitd_response_t
@@ -506,6 +512,13 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
506512
return editorOpenSwiftSourceInterface(*Name, *FileName, Args, Rec);
507513
}
508514

515+
if (ReqUID == RequestEditorOpenSwiftTypeInterface) {
516+
Optional<StringRef> Usr = Req.getString(KeyUSR);
517+
if (!Usr.hasValue())
518+
return Rec(createErrorRequestInvalid("missing 'key.usr'"));
519+
return editorOpenSwiftTypeInterface(*Usr, Args, Rec);
520+
}
521+
509522
if (ReqUID == RequestEditorExtractTextFromComment) {
510523
Optional<StringRef> Source = Req.getString(KeySourceText);
511524
if (!Source.hasValue())
@@ -1824,6 +1837,18 @@ editorOpenSwiftSourceInterface(StringRef Name, StringRef HeaderName,
18241837
Lang.editorOpenSwiftSourceInterface(Name, HeaderName, Args, EditC);
18251838
}
18261839

1840+
static void
1841+
editorOpenSwiftTypeInterface(StringRef TypeUsr, ArrayRef<const char *> Args,
1842+
ResponseReceiver Rec) {
1843+
auto EditC = std::make_shared<SKEditorConsumer>(Rec,
1844+
/*EnableSyntaxMap=*/true,
1845+
/*EnableStructure=*/true,
1846+
/*EnableDiagnostics=*/false,
1847+
/*SyntacticOnly=*/false);
1848+
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
1849+
Lang.editorOpenTypeInterface(*EditC, Args, TypeUsr);
1850+
}
1851+
18271852
static sourcekitd_response_t editorExtractTextFromComment(StringRef Source) {
18281853
SKEditorConsumer EditC(/*EnableSyntaxMap=*/false,
18291854
/*EnableStructure=*/false,

0 commit comments

Comments
 (0)