Skip to content

Commit a7e4cfd

Browse files
committed
[SourceKit] Report container type USRs in the response to cursor-info request.
Typically, users jump to type-specific interface from a member of that type, for instance, a.getSomething(). To generate the interface, we need to report the USR of the container type of "getSomething()", which is the USR for the type of a, when cursor info is requested for this function call.
1 parent a5e51a3 commit a7e4cfd

File tree

14 files changed

+140
-6
lines changed

14 files changed

+140
-6
lines changed

include/swift/AST/USRGeneration.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ enum class AccessorKind;
2323

2424
namespace ide {
2525

26+
/// Prints out the USR for the Type.
27+
/// \returns true if it failed, false on success.
28+
bool printTypeUSR(Type Ty, raw_ostream &OS);
29+
2630
/// Prints out the USR for the Type of the given decl.
2731
/// \returns true if it failed, false on success.
2832
bool printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS);

include/swift/IDE/Utils.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,13 @@ struct SemaToken {
151151
bool IsKeywordArgument = false;
152152
Type Ty;
153153
DeclContext *DC = nullptr;
154+
Type ContainerType;
154155

155156
SemaToken() = default;
156157
SemaToken(ValueDecl *ValueD, TypeDecl *CtorTyRef, SourceLoc Loc, bool IsRef,
157-
Type Ty) : ValueD(ValueD), CtorTyRef(CtorTyRef), Loc(Loc),
158-
IsRef(IsRef), Ty(Ty), DC(ValueD->getDeclContext()) {}
158+
Type Ty, Type ContainerType) : ValueD(ValueD), CtorTyRef(CtorTyRef), Loc(Loc),
159+
IsRef(IsRef), Ty(Ty), DC(ValueD->getDeclContext()),
160+
ContainerType(ContainerType) {}
159161
SemaToken(ModuleEntity Mod, SourceLoc Loc) : Mod(Mod), Loc(Loc) { }
160162

161163
bool isValid() const { return ValueD != nullptr || Mod; }
@@ -166,12 +168,14 @@ class SemaLocResolver : public SourceEntityWalker {
166168
SourceFile &SrcFile;
167169
SourceLoc LocToResolve;
168170
SemaToken SemaTok;
171+
Type ContainerType;
169172

170173
public:
171174
explicit SemaLocResolver(SourceFile &SrcFile) : SrcFile(SrcFile) { }
172175
SemaToken resolve(SourceLoc Loc);
173176
SourceManager &getSourceMgr() const;
174177
private:
178+
bool walkToExprPre(Expr *E) override;
175179
bool walkToDeclPre(Decl *D, CharSourceRange Range) override;
176180
bool walkToDeclPost(Decl *D) override;
177181
bool walkToStmtPre(Stmt *S) override;

lib/AST/USRGeneration.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ static inline StringRef getUSRSpacePrefix() {
2929
return "s:";
3030
}
3131

32+
bool ide::printTypeUSR(Type Ty, raw_ostream &OS) {
33+
using namespace Mangle;
34+
Mangler Mangler(true);
35+
Mangler.mangleType(Ty->getRValueType(), 0);
36+
Mangler.finalize(OS);
37+
return false;
38+
}
39+
3240
bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
3341
using namespace Mangle;
3442
Mangler Mangler(true);

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ SourceManager &SemaLocResolver::getSourceMgr() const
5757
}
5858

5959
bool SemaLocResolver::tryResolve(ValueDecl *D, TypeDecl *CtorTyRef,
60-
SourceLoc Loc, bool IsRef, Type Ty) {
60+
SourceLoc Loc, bool IsRef, Type Ty) {
6161
if (!D->hasName())
6262
return false;
6363

6464
if (Loc == LocToResolve) {
65-
SemaTok = { D, CtorTyRef, Loc, IsRef, Ty };
65+
SemaTok = { D, CtorTyRef, Loc, IsRef, Ty, ContainerType };
6666
return true;
6767
}
6868
return false;
@@ -138,6 +138,22 @@ bool SemaLocResolver::visitDeclReference(ValueDecl *D, CharSourceRange Range,
138138
return !tryResolve(D, CtorTyRef, Range.getStart(), /*IsRef=*/true, T);
139139
}
140140

141+
bool SemaLocResolver::walkToExprPre(Expr *E) {
142+
if (!isDone()) {
143+
if (auto SAE = dyn_cast<SelfApplyExpr>(E)) {
144+
if (SAE->getFn()->getStartLoc() == LocToResolve) {
145+
ContainerType = SAE->getBase()->getType();
146+
}
147+
} else if (auto ME = dyn_cast<MemberRefExpr>(E)) {
148+
SourceLoc DotLoc = ME->getDotLoc();
149+
if (DotLoc.isValid() && DotLoc.getAdvancedLoc(1) == LocToResolve) {
150+
ContainerType = ME->getBase()->getType();
151+
}
152+
}
153+
}
154+
return true;
155+
}
156+
141157
bool SemaLocResolver::visitCallArgName(Identifier Name, CharSourceRange Range,
142158
ValueDecl *D) {
143159
if (isDone())

test/SourceKit/CursorInfo/cursor_info.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ func rethrowingFunction1(_: (Int) throws -> Void) rethrows -> Void {}
272272
// CHECK8-NEXT: s:FC11cursor_info2CCcFT1xSi_S0_
273273
// CHECK8-NEXT: (CC.Type) -> (x: Int) -> CC
274274
// CHECK8-NEXT: _TtFT1xSi_C11cursor_info2CC
275+
// CHECK8-NEXT: <Container>C11cursor_info2CC</Container>
275276
// CHECK8-NEXT: <Declaration>convenience init(x: <Type usr="s:Si">Int</Type>)</Declaration>
276277
// CHECK8-NEXT: <decl.function.constructor><syntaxtype.keyword>convenience</syntaxtype.keyword> <syntaxtype.keyword>init</syntaxtype.keyword>(<decl.var.parameter><decl.var.parameter.argument_label>x</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter.type></decl.var.parameter>)</decl.function.constructor>
277278

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
struct S {
2+
func getArray() -> [S] { return [] }
3+
func getInstance() -> S { return self }
4+
static var Instance : S = S()
5+
}
6+
7+
class C {
8+
func getArray() -> [C] { return [] }
9+
func getInstance() -> C { return self }
10+
static var Instance : C = C()
11+
}
12+
13+
enum E {
14+
case CASE1
15+
func getArray() -> [E] { return [] }
16+
func getInstance() -> E { return self }
17+
static var Instance : E = E.CASE1
18+
}
19+
func SGen() -> S { return S() }
20+
func CGen() -> C { return C() }
21+
func EGen() -> E { return .CASE1}
22+
23+
func foo(s : S, c : C, e: E) {
24+
_ = s.getArray()
25+
_ = s.getInstance()
26+
_ = S.Instance
27+
_ = c.getArray()
28+
_ = c.getInstance()
29+
_ = C.Instance
30+
_ = e.getInstance()
31+
_ = e.getArray()
32+
_ = E.CASE1
33+
_ = E.Instance
34+
_ = SGen().getArray()
35+
_ = CGen().getInstance()
36+
_ = EGen().getArray()
37+
_ = SArrayGen().count
38+
}
39+
40+
func SArrayGen() -> [S] { return [] }
41+
42+
// RUN: %sourcekitd-test -req=cursor -pos=24:12 %s -- %s | FileCheck -check-prefix=CHECK1 %s
43+
// RUN: %sourcekitd-test -req=cursor -pos=25:12 %s -- %s | FileCheck -check-prefix=CHECK1 %s
44+
// RUN: %sourcekitd-test -req=cursor -pos=34:19 %s -- %s | FileCheck -check-prefix=CHECK1 %s
45+
// CHECK1: <Container>V21cursor_info_container1S</Container>
46+
47+
// RUN: %sourcekitd-test -req=cursor -pos=26:12 %s -- %s | FileCheck -check-prefix=CHECK2 %s
48+
// CHECK2: <Container>MV21cursor_info_container1S</Container>
49+
50+
// RUN: %sourcekitd-test -req=cursor -pos=27:12 %s -- %s | FileCheck -check-prefix=CHECK3 %s
51+
// RUN: %sourcekitd-test -req=cursor -pos=28:12 %s -- %s | FileCheck -check-prefix=CHECK3 %s
52+
// RUN: %sourcekitd-test -req=cursor -pos=35:19 %s -- %s | FileCheck -check-prefix=CHECK3 %s
53+
// CHECK3: <Container>C21cursor_info_container1C</Container>
54+
55+
// RUN: %sourcekitd-test -req=cursor -pos=29:12 %s -- %s | FileCheck -check-prefix=CHECK4 %s
56+
// CHECK4: <Container>MC21cursor_info_container1C</Container>
57+
58+
// RUN: %sourcekitd-test -req=cursor -pos=30:12 %s -- %s | FileCheck -check-prefix=CHECK5 %s
59+
// RUN: %sourcekitd-test -req=cursor -pos=31:12 %s -- %s | FileCheck -check-prefix=CHECK5 %s
60+
// RUN: %sourcekitd-test -req=cursor -pos=36:19 %s -- %s | FileCheck -check-prefix=CHECK5 %s
61+
// CHECK5: <Container>O21cursor_info_container1E</Container>
62+
63+
// RUN: %sourcekitd-test -req=cursor -pos=32:12 %s -- %s | FileCheck -check-prefix=CHECK6 %s
64+
// RUN: %sourcekitd-test -req=cursor -pos=33:12 %s -- %s | FileCheck -check-prefix=CHECK6 %s
65+
// CHECK6: <Container>MO21cursor_info_container1E</Container>
66+
67+
// RUN: %sourcekitd-test -req=cursor -pos=37:22 %s -- %s | FileCheck -check-prefix=CHECK7 %s
68+
// CHECK7: <Container>GSaV21cursor_info_container1S_</Container>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ struct CursorInfo {
254254
StringRef USR;
255255
StringRef TypeName;
256256
StringRef TypeUSR;
257+
StringRef ContainerTypeUSR;
257258
StringRef DocComment;
258259
StringRef TypeInterface;
259260
StringRef GroupName;

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,10 @@ bool SwiftLangSupport::printDeclTypeUSR(const ValueDecl *D, llvm::raw_ostream &O
701701
return ide::printDeclTypeUSR(D, OS);
702702
}
703703

704+
bool SwiftLangSupport::printTypeUSR(Type Ty, llvm::raw_ostream &OS) {
705+
return ide::printTypeUSR(Ty, OS);
706+
}
707+
704708
bool SwiftLangSupport::printAccessorUSR(const AbstractStorageDecl *D,
705709
AccessorKind AccKind,
706710
llvm::raw_ostream &OS) {

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace swift {
3434
class CompilerInstance;
3535
class CompilerInvocation;
3636
class Decl;
37+
class Type;
3738
class AbstractStorageDecl;
3839
class SourceFile;
3940
class ValueDecl;
@@ -265,6 +266,10 @@ class SwiftLangSupport : public LangSupport {
265266
/// \returns true if the results should be ignored, false otherwise.
266267
static bool printDeclTypeUSR(const swift::ValueDecl *D, llvm::raw_ostream &OS);
267268

269+
/// Generate a USR for of a given type.
270+
/// \returns true if the results should be ignored, false otherwise.
271+
static bool printTypeUSR(swift::Type Ty, llvm::raw_ostream &OS);
272+
268273
/// Generate a USR for an accessor, including the prefix.
269274
/// \returns true if the results should be ignored, false otherwise.
270275
static bool printAccessorUSR(const swift::AbstractStorageDecl *D,

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ static bool passCursorInfoForModule(ModuleEntity Mod,
612612
static bool passCursorInfoForDecl(const ValueDecl *VD,
613613
const Module *MainModule,
614614
const Type Ty,
615+
const Type ContainerTy,
615616
bool IsRef,
616617
Optional<unsigned> OrigBufferID,
617618
SwiftLangSupport &Lang,
@@ -664,6 +665,13 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
664665
}
665666
unsigned MangledTypeEnd = SS.size();
666667

668+
unsigned MangledContainerTypeStart = SS.size();
669+
if (ContainerTy) {
670+
llvm::raw_svector_ostream OS(SS);
671+
SwiftLangSupport::printTypeUSR(ContainerTy, OS);
672+
}
673+
unsigned MangedContainerTypeEnd = SS.size();
674+
667675
unsigned DocCommentBegin = SS.size();
668676
{
669677
llvm::raw_svector_ostream OS(SS);
@@ -781,6 +789,9 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
781789
TypenameEnd-TypenameBegin);
782790
StringRef TypeUsr = StringRef(SS.begin()+MangledTypeStart,
783791
MangledTypeEnd - MangledTypeStart);
792+
793+
StringRef ContainerTypeUsr = StringRef(SS.begin()+MangledContainerTypeStart,
794+
MangedContainerTypeEnd - MangledContainerTypeStart);
784795
StringRef DocComment = StringRef(SS.begin()+DocCommentBegin,
785796
DocCommentEnd-DocCommentBegin);
786797
StringRef AnnotatedDecl = StringRef(SS.begin()+DeclBegin,
@@ -822,6 +833,7 @@ static bool passCursorInfoForDecl(const ValueDecl *VD,
822833
Info.USR = USR;
823834
Info.TypeName = TypeName;
824835
Info.TypeUSR = TypeUsr;
836+
Info.ContainerTypeUSR = ContainerTypeUsr;
825837
Info.DocComment = DocComment;
826838
Info.AnnotatedDeclaration = AnnotatedDecl;
827839
Info.FullyAnnotatedDeclaration = FullyAnnotatedDecl;
@@ -957,6 +969,7 @@ static void resolveCursor(SwiftLangSupport &Lang,
957969
} else {
958970
ValueDecl *VD = SemaTok.CtorTyRef ? SemaTok.CtorTyRef : SemaTok.ValueD;
959971
bool Failed = passCursorInfoForDecl(VD, MainModule, SemaTok.Ty,
972+
SemaTok.ContainerType,
960973
SemaTok.IsRef, BufferID, Lang,
961974
CompInvok, PreviousASTSnaps,
962975
Receiver);
@@ -1021,7 +1034,7 @@ void SwiftLangSupport::getCursorInfo(
10211034
} else {
10221035
// FIXME: Should pass the main module for the interface but currently
10231036
// it's not necessary.
1024-
passCursorInfoForDecl(Entity.Dcl, /*MainModule*/nullptr, Type(),
1037+
passCursorInfoForDecl(Entity.Dcl, /*MainModule*/nullptr, Type(), Type(),
10251038
Entity.IsRef,
10261039
/*OrigBufferID=*/None, *this, Invok,
10271040
{}, Receiver);
@@ -1125,7 +1138,7 @@ resolveCursorFromUSR(SwiftLangSupport &Lang, StringRef InputFile, StringRef USR,
11251138
Receiver);
11261139
} else if (auto *VD = dyn_cast<ValueDecl>(D)) {
11271140
bool Failed =
1128-
passCursorInfoForDecl(VD, MainModule, VD->getType(),
1141+
passCursorInfoForDecl(VD, MainModule, VD->getType(), Type(),
11291142
/*isRef=*/false, BufferID, Lang, CompInvok,
11301143
PreviousASTSnaps, Receiver);
11311144
if (Failed) {

0 commit comments

Comments
 (0)