Skip to content

Commit d6f8f14

Browse files
authored
[SourceKit] Teach range-info request to recognize single declaration and multi-statements. (#5672)
1 parent ed1156b commit d6f8f14

File tree

5 files changed

+155
-35
lines changed

5 files changed

+155
-35
lines changed

include/swift/IDE/Utils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,11 @@ class SemaLocResolver : public SourceEntityWalker {
198198

199199
enum class RangeKind : int8_t{
200200
Invalid = -1,
201-
Expression,
201+
SingleExpression,
202202
SingleStatement,
203+
SingleDecl,
204+
205+
MultiStatement,
203206
};
204207

205208
struct ResolvedRangeInfo {

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -176,35 +176,102 @@ bool SemaLocResolver::visitModuleReference(ModuleEntity Mod,
176176

177177
struct RangeResolver::Implementation {
178178
SourceFile &File;
179+
private:
180+
enum class RangeMatchKind : int8_t {
181+
NoneMatch,
182+
StartMatch,
183+
EndMatch,
184+
RangeMatch,
185+
};
186+
187+
struct ContextInfo {
188+
ASTNode Parent;
189+
std::vector<ASTNode> StartMatches;
190+
std::vector<ASTNode> EndMatches;
191+
ContextInfo(ASTNode Parent) : Parent(Parent) {}
192+
};
193+
179194
SourceLoc Start;
180195
SourceLoc End;
196+
StringRef Content;
181197
Optional<ResolvedRangeInfo> Result;
182-
Implementation(SourceFile &File, SourceLoc Start, SourceLoc End) :
183-
File(File), Start(Start), End(End) {}
198+
std::vector<ContextInfo> ContextStack;
199+
ContextInfo &getCurrentDC() {
200+
assert(!ContextStack.empty());
201+
return ContextStack.back();
202+
}
184203

185-
bool isRangeMatch(SourceRange Input) {
186-
return Input.Start == Start && Input.End == End;
204+
ResolvedRangeInfo getSingleNodeKind(ASTNode Node) {
205+
assert(!Node.isNull());
206+
if (Node.is<Expr*>())
207+
return ResolvedRangeInfo(RangeKind::SingleExpression,
208+
Node.get<Expr*>()->getType(), Content);
209+
else if (Node.is<Stmt*>())
210+
return ResolvedRangeInfo(RangeKind::SingleStatement, Type(), Content);
211+
else {
212+
assert(Node.is<Decl*>());
213+
return ResolvedRangeInfo(RangeKind::SingleDecl, Type(), Content);
214+
}
215+
}
216+
217+
public:
218+
Implementation(SourceFile &File, SourceLoc Start, SourceLoc End) :
219+
File(File), Start(Start), End(End), Content(getContent()) {}
220+
~Implementation() { assert(ContextStack.empty()); }
221+
bool hasResult() { return Result.hasValue(); }
222+
void enter(ASTNode Node) { ContextStack.emplace_back(Node); }
223+
void leave() { ContextStack.pop_back(); }
224+
225+
void analyze(ASTNode Node) {
226+
auto &DCInfo = getCurrentDC();
227+
switch (getRangeMatchKind(Node.getSourceRange())) {
228+
case RangeMatchKind::NoneMatch:
229+
return;
230+
case RangeMatchKind::RangeMatch:
231+
Result = getSingleNodeKind(Node);
232+
return;
233+
case RangeMatchKind::StartMatch:
234+
DCInfo.StartMatches.emplace_back(Node);
235+
break;
236+
case RangeMatchKind::EndMatch:
237+
DCInfo.EndMatches.emplace_back(Node);
238+
break;
239+
}
240+
if (!DCInfo.StartMatches.empty() && !DCInfo.EndMatches.empty()) {
241+
Result = {RangeKind::MultiStatement, Type(), Content};
242+
return;
243+
}
187244
}
188245

189-
bool shouldEnter(SourceRange Input) {
246+
bool shouldEnter(ASTNode Node) {
190247
SourceManager &SM = File.getASTContext().SourceMgr;
191-
if (SM.isBeforeInBuffer(End, Input.Start))
248+
if (SM.isBeforeInBuffer(End, Node.getSourceRange().Start))
192249
return false;
193-
if (SM.isBeforeInBuffer(Input.End, Start))
250+
if (SM.isBeforeInBuffer(Node.getSourceRange().End, Start))
194251
return false;
195252
return true;
196253
}
197254

198-
bool hasResult() {
199-
return Result.hasValue();
200-
}
201-
202255
ResolvedRangeInfo getResult() {
203256
if (Result.hasValue())
204257
return Result.getValue();
205258
return ResolvedRangeInfo(RangeKind::Invalid, Type(), getContent());
206259
}
207260

261+
private:
262+
RangeMatchKind getRangeMatchKind(SourceRange Input) {
263+
bool StartMatch = Input.Start == Start;
264+
bool EndMatch = Input.End == End;
265+
if (StartMatch && EndMatch)
266+
return RangeMatchKind::RangeMatch;
267+
else if (StartMatch)
268+
return RangeMatchKind::StartMatch;
269+
else if (EndMatch)
270+
return RangeMatchKind::EndMatch;
271+
else
272+
return RangeMatchKind::NoneMatch;
273+
}
274+
208275
StringRef getContent() {
209276
SourceManager &SM = File.getASTContext().SourceMgr;
210277
return CharSourceRange(SM, Start, Lexer::getLocForEndOfToken(SM, End)).str();
@@ -217,45 +284,48 @@ RangeResolver::RangeResolver(SourceFile &File, SourceLoc Start, SourceLoc End) :
217284
RangeResolver::~RangeResolver() { delete &Impl; }
218285

219286
bool RangeResolver::walkToExprPre(Expr *E) {
220-
if (!Impl.shouldEnter(E->getSourceRange()))
287+
if (!Impl.shouldEnter(E))
221288
return false;
222-
if (Impl.isRangeMatch(E->getSourceRange())) {
223-
Impl.Result = ResolvedRangeInfo(RangeKind::Expression, E->getType(),
224-
Impl.getContent());
225-
}
289+
Impl.analyze(E);
290+
Impl.enter(E);
226291
return !Impl.hasResult();
227292
}
228293

229294
bool RangeResolver::walkToStmtPre(Stmt *S) {
230-
if (!Impl.shouldEnter(S->getSourceRange()))
295+
if (!Impl.shouldEnter(S))
231296
return false;
232-
if (Impl.isRangeMatch(S->getSourceRange())) {
233-
Impl.Result = ResolvedRangeInfo(RangeKind::SingleStatement, Type(),
234-
Impl.getContent());
235-
}
297+
Impl.analyze(S);
298+
Impl.enter(S);
236299
return !Impl.hasResult();
237300
};
238301

239-
240302
bool RangeResolver::walkToDeclPre(Decl *D, CharSourceRange Range) {
241-
return Impl.shouldEnter(D->getSourceRange());
303+
if (!Impl.shouldEnter(D))
304+
return false;
305+
Impl.analyze(D);
306+
Impl.enter(D);
307+
return !Impl.hasResult();
242308
}
243309

244310
bool RangeResolver::walkToExprPost(Expr *E) {
311+
Impl.leave();
245312
return !Impl.hasResult();
246313
}
247314

248315
bool RangeResolver::walkToStmtPost(Stmt *S) {
316+
Impl.leave();
249317
return !Impl.hasResult();
250318
};
251319

252320
bool RangeResolver::walkToDeclPost(Decl *D) {
321+
Impl.leave();
253322
return !Impl.hasResult();
254323
}
255324

256-
ResolvedRangeInfo
257-
RangeResolver::resolve() {
325+
ResolvedRangeInfo RangeResolver::resolve() {
326+
Impl.enter(ASTNode());
258327
walk(Impl.File);
328+
Impl.leave();
259329
return Impl.getResult();
260330
}
261331

test/SourceKit/RangeInfo/basic.swift

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,76 @@
11
func foo() -> Int{
22
var aaa = 1 + 2
33
aaa = aaa + 3
4-
if aaa = 3 { aaa = 4 }
4+
if aaa == 3 { aaa = 4 }
55
return aaa
66
}
77

8+
func foo1() -> Int { return 0 }
9+
class C { func foo() {} }
10+
struct S { func foo() {} }
11+
812
// RUN: %sourcekitd-test -req=range -pos=2:13 -length 5 %s -- %s | %FileCheck %s -check-prefix=CHECK1
913

1014
// RUN: %sourcekitd-test -req=range -pos=3:3 -length 13 %s -- %s | %FileCheck %s -check-prefix=CHECK2
1115
// RUN: %sourcekitd-test -req=range -pos=3:1 -length 15 %s -- %s | %FileCheck %s -check-prefix=CHECK2
1216

13-
// RUN: %sourcekitd-test -req=range -pos=4:1 -length 24 %s -- %s | %FileCheck %s -check-prefix=CHECK3
1417
// RUN: %sourcekitd-test -req=range -pos=4:1 -length 25 %s -- %s | %FileCheck %s -check-prefix=CHECK3
1518
// RUN: %sourcekitd-test -req=range -pos=4:1 -length 26 %s -- %s | %FileCheck %s -check-prefix=CHECK3
16-
// RUN: %sourcekitd-test -req=range -pos=4:4 -length 21 %s -- %s | %FileCheck %s -check-prefix=CHECK3
19+
// RUN: %sourcekitd-test -req=range -pos=4:1 -length 27 %s -- %s | %FileCheck %s -check-prefix=CHECK3
20+
// RUN: %sourcekitd-test -req=range -pos=4:4 -length 22 %s -- %s | %FileCheck %s -check-prefix=CHECK3
1721

1822
// RUN: %sourcekitd-test -req=range -pos=5:1 -length 12 %s -- %s | %FileCheck %s -check-prefix=CHECK4
1923
// RUN: %sourcekitd-test -req=range -pos=5:2 -length 11 %s -- %s | %FileCheck %s -check-prefix=CHECK4
2024
// RUN: %sourcekitd-test -req=range -pos=5:5 -length 8 %s -- %s | %FileCheck %s -check-prefix=CHECK4
2125
// RUN: %sourcekitd-test -req=range -pos=5:5 -length 9 %s -- %s | %FileCheck %s -check-prefix=CHECK4
2226

23-
// CHECK1-DAG: <kind>source.lang.swift.range.expression</kind>
27+
// RUN: %sourcekitd-test -req=range -pos=8:1 -length 31 %s -- %s | %FileCheck %s -check-prefix=CHECK5
28+
// RUN: %sourcekitd-test -req=range -pos=9:1 -length 25 %s -- %s | %FileCheck %s -check-prefix=CHECK6
29+
// RUN: %sourcekitd-test -req=range -pos=10:1 -length 26 %s -- %s | %FileCheck %s -check-prefix=CHECK7
30+
// RUN: %sourcekitd-test -req=range -pos=3:1 -length 42 %s -- %s | %FileCheck %s -check-prefix=CHECK8
31+
// RUN: %sourcekitd-test -req=range -pos=3:1 -length 55 %s -- %s | %FileCheck %s -check-prefix=CHECK9
32+
// RUN: %sourcekitd-test -req=range -pos=4:1 -length 36 %s -- %s | %FileCheck %s -check-prefix=CHECK10
33+
34+
// CHECK1-DAG: <kind>source.lang.swift.range.singleexpression</kind>
2435
// CHECK1-DAG: <content>1 + 2</content>
2536
// CHECK1-DAG: <type>Int</type>
2637

27-
// CHECK2-DAG: <kind>source.lang.swift.range.expression</kind>
38+
// CHECK2-DAG: <kind>source.lang.swift.range.singleexpression</kind>
2839
// CHECK2-DAG: <content>aaa = aaa + 3</content>
2940
// CHECK2-DAG: <type>()</type>
3041

3142
// CHECK3-DAG: <kind>source.lang.swift.range.singlestatement</kind>
32-
// CHECK3-DAG: <content>if aaa = 3 { aaa = 4 }</content>
43+
// CHECK3-DAG: <content>if aaa == 3 { aaa = 4 }</content>
3344
// CHECK3-DAG: <type></type>
3445

3546
// CHECK4-DAG: <kind>source.lang.swift.range.singlestatement</kind>
3647
// CHECK4-DAG: <content>return aaa</content>
3748
// CHECK4-DAG: <type></type>
49+
50+
// CHECK5-DAG: <kind>source.lang.swift.range.singledeclaration</kind>
51+
// CHECK5-DAG: <content>func foo1() -> Int { return 0 }</content>
52+
// CHECK5-DAG: <type></type>
53+
54+
// CHECK6-DAG: <kind>source.lang.swift.range.singledeclaration</kind>
55+
// CHECK6-DAG: <content>class C { func foo() {} }</content>
56+
// CHECK6-DAG: <type></type>
57+
58+
// CHECK7-DAG: <kind>source.lang.swift.range.singledeclaration</kind>
59+
// CHECK7-DAG: <content>struct S { func foo() {} }</content>
60+
// CHECK7-DAG: <type></type>
61+
62+
// CHECK8-DAG: <kind>source.lang.swift.range.multistatement</kind>
63+
// CHECK8-DAG: <content>aaa = aaa + 3
64+
// CHECK8-DAG: if aaa == 3 { aaa = 4 }</content>
65+
// CHECK8-DAG: <type></type>
66+
67+
// CHECK9-DAG: <kind>source.lang.swift.range.multistatement</kind>
68+
// CHECK9-DAG: <content>aaa = aaa + 3
69+
// CHECK9-DAG: if aaa == 3 { aaa = 4 }
70+
// CHECK9-DAG: return aaa</content>
71+
// CHECK9-DAG: <type></type>
72+
73+
// CHECK10-DAG: <kind>source.lang.swift.range.multistatement</kind>
74+
// CHECK10-DAG: <content>if aaa == 3 { aaa = 4 }
75+
// CHECK10-DAG: return aaa</content>
76+
// CHECK10-DAG: <type></type>

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,11 @@ static UIdent KindStructureElemPattern("source.lang.swift.structure.elem.pattern
154154
static UIdent KindStructureElemTypeRef("source.lang.swift.structure.elem.typeref");
155155

156156
static UIdent KindRangeSingleStatement("source.lang.swift.range.singlestatement");
157-
static UIdent KindRangeExpression("source.lang.swift.range.expression");
157+
static UIdent KindRangeSingleExpression("source.lang.swift.range.singleexpression");
158+
static UIdent KindRangeSingleDeclaration("source.lang.swift.range.singledeclaration");
159+
160+
static UIdent KindRangeMultiStatement("source.lang.swift.range.multistatement");
161+
158162
static UIdent KindRangeInvalid("source.lang.swift.range.invalid");
159163

160164
std::unique_ptr<LangSupport>
@@ -536,8 +540,10 @@ UIdent SwiftLangSupport::getUIDForSyntaxStructureElementKind(
536540
SourceKit::UIdent SwiftLangSupport::
537541
getUIDForRangeKind(swift::ide::RangeKind Kind) {
538542
switch (Kind) {
539-
case swift::ide::RangeKind::Expression: return KindRangeExpression;
543+
case swift::ide::RangeKind::SingleExpression: return KindRangeSingleExpression;
540544
case swift::ide::RangeKind::SingleStatement: return KindRangeSingleStatement;
545+
case swift::ide::RangeKind::SingleDecl: return KindRangeSingleDeclaration;
546+
case swift::ide::RangeKind::MultiStatement: return KindRangeMultiStatement;
541547
case swift::ide::RangeKind::Invalid: return KindRangeInvalid;
542548
}
543549
}

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,14 +1097,16 @@ static void resolveRange(SwiftLangSupport &Lang,
10971097
Result.RangeKind = Lang.getUIDForRangeKind(Info.Kind);
10981098
Result.RangeContent = Info.Content;
10991099
switch (Info.Kind) {
1100-
case RangeKind::Expression: {
1100+
case RangeKind::SingleExpression: {
11011101
SmallString<64> SS;
11021102
llvm::raw_svector_ostream OS(SS);
11031103
Info.Ty.print(OS);
11041104
Result.ExprType = OS.str();
11051105
Receiver(Result);
11061106
return;
11071107
}
1108+
case RangeKind::SingleDecl:
1109+
case RangeKind::MultiStatement:
11081110
case RangeKind::SingleStatement: {
11091111
Receiver(Result);
11101112
return;

0 commit comments

Comments
 (0)