Skip to content

Commit effab8c

Browse files
committed
Handle dynamic member lookup in annotation and cursor info
Ensure the various entity walkers handle the implicit subscript reference correctly (usually by ignoring it) and fall through to the underlying declarations. rdar://49028895
1 parent 6af24d0 commit effab8c

File tree

7 files changed

+106
-5
lines changed

7 files changed

+106
-5
lines changed

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ bool CursorInfoResolver::visitDeclReference(ValueDecl *D,
190190
ReferenceMetaData Data) {
191191
if (isDone())
192192
return false;
193+
if (Data.isImplicit)
194+
return true;
193195
return !tryResolve(D, CtorTyRef, ExtTyRef, Range.getStart(), /*IsRef=*/true, T);
194196
}
195197

@@ -1423,7 +1425,7 @@ struct RangeResolver::Implementation {
14231425
if (Data.Kind != SemaReferenceKind::DeclRef)
14241426
return;
14251427

1426-
if (!isContainedInSelection(CharSourceRange(Start, 0)))
1428+
if (Data.isImplicit || !isContainedInSelection(CharSourceRange(Start, 0)))
14271429
return;
14281430

14291431
// If the VD is declared outside of current file, exclude such decl.

lib/Migrator/APIDiffMigratorPass.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
484484
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
485485
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef,
486486
Type T, ReferenceMetaData Data) override {
487+
if (Data.isImplicit)
488+
return true;
489+
487490
for (auto *Item: getRelatedDiffItems(CtorTyRef ? CtorTyRef: D)) {
488491
std::string RepText;
489492
if (isSimpleReplacement(Item, isDotMember(Range), RepText)) {
@@ -501,7 +504,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
501504
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
502505
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef,
503506
Type T, ReferenceMetaData Data) override {
504-
if (D == Target) {
507+
if (D == Target && !Data.isImplicit) {
505508
Result = Range;
506509
return false;
507510
}

test/IDE/annotation.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,30 @@ test_arg_tuple2(p1:0,0)
339339
test_arg_tuple3(0,p2:0)
340340
// CHECK: <Func@[[@LINE-7]]:6>test_arg_tuple4</Func>(<Func@[[@LINE-7]]:6#p1>p1</Func>:0,<Func@[[@LINE-7]]:6#p2>p2</Func>:0)
341341
test_arg_tuple4(p1:0,p2:0)
342+
343+
344+
@dynamicMemberLookup
345+
struct Lens<T> {
346+
var obj: T
347+
init(_ obj: T) {
348+
self.obj = obj
349+
}
350+
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> Lens<U> {
351+
get { return Lens<U>(obj[keyPath: member]) }
352+
set { obj[keyPath: member] = newValue.obj }
353+
}
354+
}
355+
struct Point {
356+
var x: Int
357+
var y: Int
358+
}
359+
struct Rectangle {
360+
var topLeft: Point
361+
var bottomRight: Point
362+
}
363+
func testDynamicMemberLookup(r: Lens<Rectangle>) {
364+
_ = r.topLeft
365+
// CHECK: _ = <Param@[[@LINE-2]]:30>r</Param>.<Var@[[@LINE-5]]:7>topLeft</Var>
366+
_ = r.bottomRight.y
367+
// CHECK: _ = <Param@[[@LINE-4]]:30>r</Param>.<Var@[[@LINE-6]]:7>bottomRight</Var>.<Var@[[@LINE-10]]:7>y</Var>
368+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
struct Point {
2+
var x: Int
3+
var y: Int
4+
}
5+
6+
struct Rectangle {
7+
var topLeft: Point
8+
var bottomRight: Point
9+
}
10+
11+
@dynamicMemberLookup
12+
struct Lens<T> {
13+
var obj: T
14+
init(_ obj: T) {
15+
self.obj = obj
16+
}
17+
18+
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> Lens<U> {
19+
get { return Lens<U>(obj[keyPath: member]) }
20+
set { obj[keyPath: member] = newValue.obj }
21+
}
22+
}
23+
24+
func test(r: Lens<Rectangle>) {
25+
_ = r.topLeft
26+
_ = r.bottomRight.y
27+
}
28+
29+
// RUN: %sourcekitd-test -req=cursor -pos=18:3 -cursor-action %s -- %s | %FileCheck -check-prefix=SUBSCRIPT %s
30+
// SUBSCRIPT: source.lang.swift.decl.function.subscript (18:3-18:12)
31+
// SUBSCRIPT: subscript(dynamicMember:)
32+
// SUBSCRIPT: <T, U> (dynamicMember: WritableKeyPath<T, U>) -> Lens<U>
33+
// SUBSCRIPT: <decl.function.subscript><syntaxtype.keyword>subscript</syntaxtype.keyword>&lt;<decl.generic_type_param usr="s:33cursor_info_keypath_member_lookup4LensV1UL_qd__mfp"><decl.generic_type_param.name>U</decl.generic_type_param.name></decl.generic_type_param>&gt;(<decl.var.parameter><decl.var.parameter.argument_label>dynamicMember</decl.var.parameter.argument_label> <decl.var.parameter.name>member</decl.var.parameter.name>: <decl.var.parameter.type><ref.class usr="s:s15WritableKeyPathC">WritableKeyPath</ref.class>&lt;<ref.generic_type_param usr="s:33cursor_info_keypath_member_lookup4LensV1Txmfp">T</ref.generic_type_param>, <ref.generic_type_param usr="s:33cursor_info_keypath_member_lookup4LensV1UL_qd__mfp">U</ref.generic_type_param>&gt;</decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype><ref.struct usr="s:33cursor_info_keypath_member_lookup4LensV">Lens</ref.struct>&lt;<ref.generic_type_param usr="s:33cursor_info_keypath_member_lookup4LensV1UL_qd__mfp">U</ref.generic_type_param>&gt;</decl.function.returntype> { <syntaxtype.keyword>get</syntaxtype.keyword> <syntaxtype.keyword>set</syntaxtype.keyword> }</decl.function.subscript>
34+
// SUBSCRIPT: ACTIONS BEGIN
35+
// FIXME: should not allow rename since that would break the contract.
36+
// SUBSCRIPT: source.refactoring.kind.rename.global
37+
// SUBSCRIPT: ACTIONS END
38+
39+
// RUN: %sourcekitd-test -req=cursor -pos=25:9 -cursor-action %s -- %s | %FileCheck -check-prefix=TOP_LEFT %s
40+
// TOP_LEFT: source.lang.swift.ref.var.instance
41+
// TOP_LEFT: topLeft
42+
// TOP_LEFT: Point
43+
// TOP_LEFT: <decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>topLeft</decl.name>: <decl.var.type><ref.struct usr="{{s:.*}}">Point</ref.struct></decl.var.type></decl.var.instance>
44+
// TOP_LEVEL: ACTIONS BEGIN
45+
// TOP_LEVEL: source.refactoring.kind.rename.global
46+
// TOP_LEVEL: ACTIONS END
47+
48+
// RUN: %sourcekitd-test -req=cursor -pos=26:9 -cursor-action %s -- %s | %FileCheck -check-prefix=BOTTOM_RIGHT %s
49+
// BOTTOM_RIGHT: source.lang.swift.ref.var.instance
50+
// BOTTOM_RIGHT: bottomRight
51+
// BOTTOM_RIGHT: Point
52+
// BOTTOM_RIGHT: ACTIONS BEGIN
53+
// BOTTOM_RIGHT: source.refactoring.kind.rename.global
54+
// BOTTOM_RIGHT: ACTIONS END
55+
56+
/// RUN: %sourcekitd-test -req=cursor -pos=26:21 -cursor-action %s -- %s | %FileCheck -check-prefix=YREF %s
57+
// YREF: source.lang.swift.ref.var.instance
58+
// YREF: y
59+
// YREF: Int
60+
// YREF: <decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>y</decl.name>: <decl.var.type><ref.struct usr="s:Si">Int</ref.struct></decl.var.type></decl.var.instance>
61+
// YREF: ACTIONS BEGIN
62+
// YREF: source.refactoring.kind.rename.global
63+
// YREF: ACTIONS END

tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,8 @@ class SourceDocASTWalker : public SourceEntityWalker {
10321032
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
10331033
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type Ty,
10341034
ReferenceMetaData Data) override {
1035+
if (Data.isImplicit)
1036+
return true;
10351037
unsigned StartOffset = getOffset(Range.getStart());
10361038
References.emplace_back(D, StartOffset, Range.getByteLength(), Ty);
10371039
return true;

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,11 @@ class SemanticAnnotator : public SourceEntityWalker {
905905
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
906906
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type T,
907907
ReferenceMetaData Data) override {
908-
if (isa<VarDecl>(D) && D->hasName() &&
909-
D->getFullName() == D->getASTContext().Id_self)
908+
if (Data.isImplicit)
909+
return true;
910+
911+
if (isa<VarDecl>(D) && D->hasName() &&
912+
D->getFullName() == D->getASTContext().Id_self)
910913
return true;
911914

912915
// Do not annotate references to unavailable decls.

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,8 @@ class AnnotationPrinter : public SourceEntityWalker {
14341434
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
14351435
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type Ty,
14361436
ReferenceMetaData Data) override {
1437-
annotateSourceEntity({ Range, D, CtorTyRef, /*IsRef=*/true });
1437+
if (!Data.isImplicit)
1438+
annotateSourceEntity({ Range, D, CtorTyRef, /*IsRef=*/true });
14381439
return true;
14391440
}
14401441

0 commit comments

Comments
 (0)