Skip to content

Commit 0b9aac0

Browse files
author
Nathan Hawes
committed
[sourcekitd][RelatedIdents] Fix handling of var decls in fallthrough case statements
We weren't picking up all occurrences of 'x' in the cases like the below: case .first(let x), .second(let x): print("foo \(x)") fallthrough case .third(let x): print("bar \(x)") We would previously only return occurrences within the case statement the query was made in (ignoring fallthroughs) and for cases with multiple patterns (as in the first case above) we would only return the occurrence in the first pattern.
1 parent 1d4e666 commit 0b9aac0

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

test/SourceKit/RelatedIdents/related_idents.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,27 @@ class C2<Param> {
2323
func f(t : Param) -> Param {return t}
2424
}
2525

26+
enum X {
27+
case first(Int, String)
28+
case second(Int, String)
29+
case third(Int, String)
30+
case fourth(Int, String)
31+
}
32+
33+
switch X.first(2, "") {
34+
case .first(let x, let y):
35+
print(y)
36+
fallthrough
37+
case .second(let x, _):
38+
print(x)
39+
case .third(let x, let y):
40+
fallthrough
41+
case .fourth(let x, let y):
42+
print(y)
43+
print(x)
44+
break
45+
}
46+
2647
// RUN: %sourcekitd-test -req=related-idents -pos=6:17 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK1 %s
2748
// CHECK1: START RANGES
2849
// CHECK1-NEXT: 1:7 - 2
@@ -53,3 +74,37 @@ class C2<Param> {
5374
// CHECK5-NEXT: 23:13 - 5
5475
// CHECK5-NEXT: 23:23 - 5
5576
// CHECK5-NEXT: END RANGES
77+
78+
// RUN: %sourcekitd-test -req=related-idents -pos=34:19 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK6 %s
79+
// RUN: %sourcekitd-test -req=related-idents -pos=37:20 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK6 %s
80+
// RUN: %sourcekitd-test -req=related-idents -pos=38:11 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK6 %s
81+
// CHECK6: START RANGES
82+
// CHECK6-NEXT: 34:19 - 1
83+
// CHECK6-NEXT: 37:20 - 1
84+
// CHECK6-NEXT: 38:11 - 1
85+
// CHECK6-NEXT: END RANGES
86+
87+
// RUN: %sourcekitd-test -req=related-idents -pos=34:26 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK7 %s
88+
// RUN: %sourcekitd-test -req=related-idents -pos=35:11 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK7 %s
89+
// CHECK7: START RANGES
90+
// CHECK7-NEXT: 34:26 - 1
91+
// CHECK7-NEXT: 35:11 - 1
92+
// CHECK7-NEXT: END RANGES
93+
94+
// RUN: %sourcekitd-test -req=related-idents -pos=39:26 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK8 %s
95+
// RUN: %sourcekitd-test -req=related-idents -pos=41:27 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK8 %s
96+
// RUN: %sourcekitd-test -req=related-idents -pos=42:11 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK8 %s
97+
// CHECK8: START RANGES
98+
// CHECK8-NEXT: 39:26 - 1
99+
// CHECK8-NEXT: 41:27 - 1
100+
// CHECK8-NEXT: 42:11 - 1
101+
// CHECK8-NEXT: END RANGES
102+
103+
// RUN: %sourcekitd-test -req=related-idents -pos=39:19 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK9 %s
104+
// RUN: %sourcekitd-test -req=related-idents -pos=41:20 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK9 %s
105+
// RUN: %sourcekitd-test -req=related-idents -pos=43:11 %s -- -module-name related_idents %s | %FileCheck -check-prefix=CHECK9 %s
106+
// CHECK9: START RANGES
107+
// CHECK9-NEXT: 39:19 - 1
108+
// CHECK9-NEXT: 41:20 - 1
109+
// CHECK9-NEXT: 43:11 - 1
110+
// CHECK9-NEXT: END RANGES

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,15 +1838,27 @@ class RelatedIdScanner : public SourceEntityWalker {
18381838
explicit RelatedIdScanner(SourceFile &SrcFile, unsigned BufferID,
18391839
ValueDecl *D,
18401840
llvm::SmallVectorImpl<std::pair<unsigned, unsigned>> &Ranges)
1841-
: Dcl(D), Ranges(Ranges),
1842-
SourceMgr(SrcFile.getASTContext().SourceMgr),
1841+
: Ranges(Ranges), SourceMgr(SrcFile.getASTContext().SourceMgr),
18431842
BufferID(BufferID) {
1843+
if (auto *V = dyn_cast<VarDecl>(D)) {
1844+
// Always use the canonical var decl for comparison. This is so we
1845+
// pick up all occurrences of x in case statements like the below:
1846+
// case .first(let x), .second(let x)
1847+
// fallthrough
1848+
// case .third(let x)
1849+
// print(x)
1850+
Dcl = V->getCanonicalVarDecl();
1851+
} else {
1852+
Dcl = D;
1853+
}
18441854
}
18451855

18461856
private:
18471857
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
18481858
if (Cancelled)
18491859
return false;
1860+
if (auto *V = dyn_cast<VarDecl>(D))
1861+
D = V->getCanonicalVarDecl();
18501862
if (D == Dcl)
18511863
return passId(Range);
18521864
return true;
@@ -1856,8 +1868,12 @@ class RelatedIdScanner : public SourceEntityWalker {
18561868
ReferenceMetaData Data) override {
18571869
if (Cancelled)
18581870
return false;
1859-
if (CtorTyRef)
1871+
1872+
if (auto *V = dyn_cast<VarDecl>(D))
1873+
D = V->getCanonicalVarDecl();
1874+
else if (CtorTyRef)
18601875
D = CtorTyRef;
1876+
18611877
if (D == Dcl)
18621878
return passId(Range);
18631879
return true;
@@ -1933,7 +1949,13 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
19331949
return;
19341950

19351951
RelatedIdScanner Scanner(SrcFile, BufferID, VD, Ranges);
1936-
if (DeclContext *LocalDC = VD->getDeclContext()->getLocalContext()) {
1952+
1953+
if (auto *Case = getCaseStmtOfCanonicalVar(VD)) {
1954+
Scanner.walk(Case);
1955+
while ((Case = Case->getFallthroughDest().getPtrOrNull())) {
1956+
Scanner.walk(Case);
1957+
}
1958+
} else if (DeclContext *LocalDC = VD->getDeclContext()->getLocalContext()) {
19371959
Scanner.walk(LocalDC);
19381960
} else {
19391961
Scanner.walk(SrcFile);
@@ -1956,6 +1978,16 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
19561978
LOG_WARN_FUNC("related idents failed: " << Error);
19571979
Receiver({});
19581980
}
1981+
1982+
static CaseStmt *getCaseStmtOfCanonicalVar(Decl *D) {
1983+
assert(D);
1984+
if (auto *VD = dyn_cast<VarDecl>(D)) {
1985+
if (auto *Canonical = VD->getCanonicalVarDecl()) {
1986+
return dyn_cast_or_null<CaseStmt>(Canonical->getRecursiveParentPatternStmt());
1987+
}
1988+
}
1989+
return nullptr;
1990+
}
19591991
};
19601992

19611993
auto Consumer = std::make_shared<RelatedIdConsumer>(Offset, Receiver, Invok);

0 commit comments

Comments
 (0)