Skip to content

Commit bba2f47

Browse files
authored
Merge pull request #67613 from barinsim/my-main
[SourceKit] Report cursor info information for literals
2 parents b741299 + 9342e78 commit bba2f47

File tree

6 files changed

+250
-14
lines changed

6 files changed

+250
-14
lines changed

lib/IDE/IDERequests.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,13 @@ ResolvedCursorInfoPtr CursorInfoResolver::resolve(SourceLoc Loc) {
229229
}
230230

231231
bool CursorInfoResolver::walkToDeclPre(Decl *D, CharSourceRange Range) {
232-
if (!rangeContainsLoc(D->getSourceRangeIncludingAttrs()))
232+
// Get char based source range for this declaration.
233+
SourceRange SR = D->getSourceRangeIncludingAttrs();
234+
auto &Context = D->getASTContext();
235+
CharSourceRange CharSR =
236+
Lexer::getCharSourceRangeFromSourceRange(Context.SourceMgr, SR);
237+
238+
if (!rangeContainsLoc(CharSR))
233239
return false;
234240

235241
if (isa<ExtensionDecl>(D))

test/SourceKit/CursorInfo/cursor_info.swift

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ enum E7: String {
230230

231231
func checkAnyIsAKeyword(x: Any) {}
232232

233+
var binExpr = 1 + 2 + 3
234+
235+
struct A: ExpressibleByIntegerLiteral {
236+
init(integerLiteral value: Int) {
237+
self.value = value
238+
}
239+
let value: Int
240+
}
241+
var a: A = 42
242+
243+
let stringStr = "str"
244+
let strInterpolation = "This is a \(stringStr + "ing") interpolation"
245+
233246
// REQUIRES: objc_interop
234247
// RUN: %empty-directory(%t.tmp)
235248
// RUN: %swiftc_driver -emit-module -o %t.tmp/FooSwiftModule.swiftmodule %S/Inputs/FooSwiftModule.swift
@@ -804,8 +817,71 @@ func checkAnyIsAKeyword(x: Any) {}
804817
// CHECK93-NEXT: <decl.enumelement><syntaxtype.keyword>case</syntaxtype.keyword> <decl.name>b</decl.name> = <syntaxtype.string>&quot;f&quot;</syntaxtype.string></decl.enumelement>
805818

806819
// RUN: %sourcekitd-test -req=cursor -pos=227:14 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK94 %s
807-
// CHECK94: <empty cursor info; internal diagnostic: "Resolved to incomplete expression or statement.">
820+
// CHECK94: source.lang.swift.ref.struct
821+
// CHECK94-NEXT: String
822+
// CHECK94-NEXT: s:SS
823+
// CHECK94-NEXT: source.lang.swift
824+
// CHECK94-NEXT: String.Type
825+
// CHECK94-NEXT: $sSSmD
826+
// CHECK94-NEXT: Swift
827+
// CHECK94-NEXT: <Group>String</Group>
828+
// CHECK94-NEXT: SYSTEM
829+
// CHECK94-NEXT: <Declaration>@frozen @_eagerMove struct String</Declaration>
808830

809831
// RUN: %sourcekitd-test -req=cursor -pos=231:6 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK95 %s
810832
// CHECK95: <Declaration>func checkAnyIsAKeyword(x: Any)</Declaration>
811833
// CHECK95-NEXT: <decl.function.free><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>checkAnyIsAKeyword</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>x</decl.var.parameter.argument_label>: <decl.var.parameter.type><syntaxtype.keyword>Any</syntaxtype.keyword></decl.var.parameter.type></decl.var.parameter>)</decl.function.free>
834+
835+
// RUN: %sourcekitd-test -req=cursor -pos=23:23 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK96 %s
836+
// CHECK96: source.lang.swift.ref.struct
837+
// CHECK96-NEXT: String
838+
// CHECK96-NEXT: s:SS
839+
// CHECK96-NEXT: source.lang.swift
840+
// CHECK96-NEXT: String.Type
841+
// CHECK96-NEXT: $sSSmD
842+
// CHECK96-NEXT: Swift
843+
// CHECK96-NEXT: <Group>String</Group>
844+
// CHECK96-NEXT: SYSTEM
845+
// CHECK96-NEXT: <Declaration>@frozen @_eagerMove struct String</Declaration>
846+
847+
// RUN: %sourcekitd-test -req=cursor -pos=233:19 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK97 %s
848+
// CHECK97: source.lang.swift.ref.struct
849+
// CHECK97-NEXT: Int
850+
// CHECK97-NEXT: s:Si
851+
// CHECK97-NEXT: source.lang.swift
852+
// CHECK97-NEXT: Int.Type
853+
// CHECK97-NEXT: $sSimD
854+
// CHECK97-NEXT: Swift
855+
// CHECK97-NEXT: <Group>Math/Integers</Group>
856+
// CHECK97-NEXT: SYSTEM
857+
858+
// RUN: %sourcekitd-test -req=cursor -pos=241:12 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK98 %s
859+
// CHECK98: source.lang.swift.ref.function.constructor (236:5-236:36)
860+
// CHECK98-NEXT: init(integerLiteral:)
861+
// CHECK98-NEXT: s:11cursor_info1AV14integerLiteralACSi_tcfc
862+
// CHECK98-NEXT: source.lang.swift
863+
// CHECK98-NEXT: (A.Type) -> (Int) -> A
864+
// CHECK98-NEXT: $s14integerLiteral11cursor_info1AVSi_tcD
865+
// CHECK98-NEXT: cursor_info
866+
867+
// RUN: %sourcekitd-test -req=cursor -pos=244:51 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK99 %s
868+
// CHECK99: source.lang.swift.ref.struct ()
869+
// CHECK99-NEXT: String
870+
// CHECK99-NEXT: s:SS
871+
// CHECK99-NEXT: source.lang.swift
872+
// CHECK99-NEXT: String.Type
873+
// CHECK99-NEXT: $sSSmD
874+
// CHECK99-NEXT: Swift
875+
// CHECK99-NEXT: <Group>String</Group>
876+
// CHECK99-NEXT: SYSTEM
877+
878+
// RUN: %sourcekitd-test -req=cursor -pos=244:61 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK100 %s
879+
// CHECK100: source.lang.swift.ref.function.constructor ()
880+
// CHECK100-NEXT: init(stringInterpolation:)
881+
// CHECK100-NEXT: s:SS19stringInterpolationSSs013DefaultStringB0V_tcfc
882+
// CHECK100-NEXT: source.lang.swift
883+
// CHECK100-NEXT: (String.Type) -> (DefaultStringInterpolation) -> String
884+
// CHECK100-NEXT: $s19stringInterpolationSSs013DefaultStringB0V_tcD
885+
// CHECK100-NEXT: Swift
886+
// CHECK100-NEXT: <Group>String</Group>
887+
// CHECK100-NEXT: SYSTEM

test/SourceKit/CursorInfo/cursor_stdlib.swift

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ func foo2(_ a : inout [S1]) {
2121
import Swift
2222
func foo3(a: Float, b: Bool) {}
2323

24+
struct MyColor: _ExpressibleByColorLiteral {
25+
init(_colorLiteralRed: Float, green: Float, blue: Float, alpha: Float) { red = colorLiteralRed }
26+
var red: Float
27+
}
28+
public typealias _ColorLiteralType = MyColor
29+
let colorResource = #colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1)
30+
31+
let arrLiteral = [1, 2, 3]
32+
let arrNonConst = [1, 2, d]
33+
34+
let dictLiteral = [1:2, 3:4]
35+
let dictNonCost = [1:2, 3:d]
36+
2437
// REQUIRES: objc_interop
2538

2639
// RUN: %empty-directory(%t)
@@ -222,3 +235,58 @@ func foo3(a: Float, b: Bool) {}
222235

223236
// RUN: %sourcekitd-test -req=cursor -pos=22:25 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-BOOL1 %s
224237
// CHECK-BOOL1: s:Sb
238+
239+
// RUN: %sourcekitd-test -req=cursor -pos=29:29 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-OBJ-LITERAL %s
240+
// CHECK-OBJ-LITERAL: source.lang.swift.ref.struct (24:8-24:15)
241+
// CHECK-OBJ-LITERAL-NEXT: MyColor
242+
// CHECK-OBJ-LITERAL-NEXT: s:13cursor_stdlib7MyColorV
243+
// CHECK-OBJ-LITERAL-NEXT: source.lang.swift
244+
// CHECK-OBJ-LITERAL-NEXT: MyColor.Type
245+
// CHECK-OBJ-LITERAL-NEXT: $s13cursor_stdlib7MyColorVmD
246+
// CHECK-OBJ-LITERAL-NEXT: cursor_stdlib
247+
// CHECK-OBJ-LITERAL-NEXT: <Declaration>struct MyColor : <Type usr="s:s26_ExpressibleByColorLiteralP">_ExpressibleByColorLiteral</Type></Declaration>
248+
// CHECK-OBJ-LITERAL-NEXT: <decl.struct><syntaxtype.keyword>struct</syntaxtype.keyword> <decl.name>MyColor</decl.name> : <ref.protocol usr="s:s26_ExpressibleByColorLiteralP">_ExpressibleByColorLiteral</ref.protocol></decl.struct>
249+
250+
// RUN: %sourcekitd-test -req=cursor -pos=31:18 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-ARRAY1 %s
251+
// CHECK-ARRAY1: source.lang.swift.ref.function.constructor
252+
// CHECK-ARRAY1-NEXT: init(arrayLiteral:)
253+
// CHECK-ARRAY1-NEXT: s:Sa12arrayLiteralSayxGxd_tcfc
254+
// CHECK-ARRAY1-NEXT: source.lang.swift
255+
// CHECK-ARRAY1-NEXT: <Element> (Array<Element>.Type) -> (Element...) -> Array<Element>
256+
// CHECK-ARRAY1-NEXT: $s12arrayLiteralSayxGxd_tcD
257+
// CHECK-ARRAY1-NEXT: Swift
258+
// CHECK-ARRAY1-NEXT: <Group>Collection/Array</Group>
259+
// CHECK-ARRAY1-NEXT: SYSTEM
260+
261+
// RUN: %sourcekitd-test -req=cursor -pos=32:19 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-ARRAY2 %s
262+
// CHECK-ARRAY2: source.lang.swift.ref.function.constructor
263+
// CHECK-ARRAY2-NEXT: init(arrayLiteral:)
264+
// CHECK-ARRAY2-NEXT: s:Sa12arrayLiteralSayxGxd_tcfc
265+
// CHECK-ARRAY2-NEXT: source.lang.swift
266+
// CHECK-ARRAY2-NEXT: <Element> (Array<Element>.Type) -> (Element...) -> Array<Element>
267+
// CHECK-ARRAY2-NEXT: $s12arrayLiteralSayxGxd_tcD
268+
// CHECK-ARRAY2-NEXT: Swift
269+
// CHECK-ARRAY2-NEXT: <Group>Collection/Array</Group>
270+
// CHECK-ARRAY2-NEXT: SYSTEM
271+
272+
// RUN: %sourcekitd-test -req=cursor -pos=34:19 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-DICT1 %s
273+
// CHECK-DICT1: source.lang.swift.ref.function.constructor
274+
// CHECK-DICT1-NEXT: init(dictionaryLiteral:)
275+
// CHECK-DICT1-NEXT: s:SD17dictionaryLiteralSDyxq_Gx_q_td_tcfc
276+
// CHECK-DICT1-NEXT: source.lang.swift
277+
// CHECK-DICT1-NEXT: <Key, Value where Key : Hashable> (Dictionary<Key, Value>.Type) -> ((Key, Value)...) -> Dictionary<Key, Value>
278+
// CHECK-DICT1-NEXT: $s17dictionaryLiteralSDyxq_Gx_q_td_tcD
279+
// CHECK-DICT1-NEXT: Swift
280+
// CHECK-DICT1-NEXT: <Group>Collection/HashedCollections</Group>
281+
// CHECK-DICT1-NEXT: SYSTEM
282+
283+
// RUN: %sourcekitd-test -req=cursor -pos=35:19 %s -- %s -target %target-triple %clang-importer-sdk-nosource -I %t | %FileCheck -check-prefix=CHECK-DICT2 %s
284+
// CHECK-DICT2: source.lang.swift.ref.function.constructor
285+
// CHECK-DICT2-NEXT: init(dictionaryLiteral:)
286+
// CHECK-DICT2-NEXT: s:SD17dictionaryLiteralSDyxq_Gx_q_td_tcfc
287+
// CHECK-DICT2-NEXT: source.lang.swift
288+
// CHECK-DICT2-NEXT: <Key, Value where Key : Hashable> (Dictionary<Key, Value>.Type) -> ((Key, Value)...) -> Dictionary<Key, Value>
289+
// CHECK-DICT2-NEXT: $s17dictionaryLiteralSDyxq_Gx_q_td_tcD
290+
// CHECK-DICT2-NEXT: Swift
291+
// CHECK-DICT2-NEXT: <Group>Collection/HashedCollections</Group>
292+
// CHECK-DICT2-NEXT: SYSTEM

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,11 @@ struct CursorInfoData {
685685
/// \c CursorInfoData.
686686
llvm::BumpPtrAllocator Allocator;
687687

688+
bool isEmpty() const {
689+
return InternalDiagnostic.empty() && Symbols.empty() &&
690+
AvailableActions.empty();
691+
}
692+
688693
void print(llvm::raw_ostream &OS, std::string Indentation) const {
689694
OS << Indentation << "CursorInfoData" << '\n';
690695
OS << Indentation << " Symbols:" << '\n';

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,66 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
11511151
return llvm::Error::success();
11521152
}
11531153

1154+
// If \p E is a literal, returns the declaration that should be reported by
1155+
// cursor info for that initializer.
1156+
static ValueDecl *getCursorInfoDeclForLiteral(Expr *E) {
1157+
if (auto *CollectionLit = dyn_cast<CollectionExpr>(E)) {
1158+
return CollectionLit->getInitializer().getDecl();
1159+
}
1160+
1161+
LiteralExpr* LitExpr = dyn_cast<LiteralExpr>(E);
1162+
if (!LitExpr) {
1163+
return nullptr;
1164+
}
1165+
1166+
bool IsObjectLiteral = isa<ObjectLiteralExpr>(E);
1167+
if (!IsObjectLiteral && LitExpr->getInitializer().getDecl()) {
1168+
return LitExpr->getInitializer().getDecl();
1169+
}
1170+
1171+
// We shouldn’t report the builtin initializer to the user because it’s
1172+
// underscored and not visible. Instead, return the type of the literal.
1173+
if (IsObjectLiteral || isa<BuiltinLiteralExpr>(E)) {
1174+
Type Ty = E->getType();
1175+
if (!Ty) {
1176+
return nullptr;
1177+
}
1178+
auto NominalTy = Ty->getAs<NominalOrBoundGenericNominalType>();
1179+
if (!NominalTy) {
1180+
return nullptr;
1181+
}
1182+
return NominalTy->getDecl();
1183+
}
1184+
return nullptr;
1185+
}
1186+
1187+
static bool addCursorInfoForLiteral(
1188+
CursorInfoData &Data, Expr *LitExpr, SwiftLangSupport &Lang,
1189+
const CompilerInvocation &CompInvoc, SourceLoc CursorLoc,
1190+
ArrayRef<ImmutableTextSnapshotRef> PreviousSnaps) {
1191+
if (!LitExpr) {
1192+
return false;
1193+
}
1194+
1195+
ValueDecl *Decl = getCursorInfoDeclForLiteral(LitExpr);
1196+
if (!Decl) {
1197+
return false;
1198+
}
1199+
1200+
auto &Symbol = Data.Symbols.emplace_back();
1201+
DeclInfo Info(Decl, nullptr, true, false, {}, CompInvoc);
1202+
auto Err = fillSymbolInfo(Symbol, Info, CursorLoc, false, Lang, CompInvoc,
1203+
PreviousSnaps, Data.Allocator);
1204+
1205+
bool Success = true;
1206+
llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &E) {
1207+
Data.InternalDiagnostic = copyCString(E.getMessage(), Data.Allocator);
1208+
Data.Symbols.pop_back();
1209+
Success = false;
1210+
});
1211+
return Success;
1212+
}
1213+
11541214
static bool
11551215
addCursorInfoForDecl(CursorInfoData &Data, ResolvedValueRefCursorInfoPtr Info,
11561216
bool AddRefactorings, bool AddSymbolGraph,
@@ -1202,7 +1262,8 @@ addCursorInfoForDecl(CursorInfoData &Data, ResolvedValueRefCursorInfoPtr Info,
12021262
fillSymbolInfo(SymbolInfo, DInfo, Info->getLoc(), AddSymbolGraph,
12031263
Lang, Invoc, PreviousSnaps, Data.Allocator)) {
12041264
// Ignore but make sure to remove the partially-filled symbol
1205-
llvm::handleAllErrors(std::move(Err), [](const llvm::StringError &E) {});
1265+
llvm::handleAllErrors(std::move(Err),
1266+
[](const llvm::StringError &E) {});
12061267
Data.Symbols.pop_back();
12071268
}
12081269
}
@@ -1630,21 +1691,40 @@ static void resolveCursor(
16301691
}
16311692
case CursorInfoKind::ExprStart:
16321693
case CursorInfoKind::StmtStart: {
1694+
// If code under cursor is literal expression returns Expr,
1695+
// otherwise nullptr.
1696+
auto tryGetLiteralExpr = [](auto CI) -> Expr * {
1697+
auto *ExprInfo = dyn_cast<ResolvedExprStartCursorInfo>(CI);
1698+
if (!ExprInfo || !ExprInfo->getTrailingExpr()) {
1699+
return nullptr;
1700+
}
1701+
Expr *E = ExprInfo->getTrailingExpr();
1702+
if (dyn_cast<LiteralExpr>(E) || dyn_cast<CollectionExpr>(E)) {
1703+
return E;
1704+
}
1705+
return nullptr;
1706+
};
1707+
1708+
CursorInfoData Data;
1709+
16331710
if (Actionables) {
16341711
addRefactorings(
16351712
Actions, collectRefactorings(CursorInfo, /*ExcludeRename=*/true));
1636-
if (!Actions.empty()) {
1637-
CursorInfoData Data;
1638-
Data.AvailableActions = Actions;
1639-
Receiver(RequestResult<CursorInfoData>::fromResult(Data));
1640-
return;
1641-
}
1713+
Data.AvailableActions = Actions;
16421714
}
16431715

1644-
CursorInfoData Info;
1645-
Info.InternalDiagnostic =
1646-
"Resolved to incomplete expression or statement.";
1647-
Receiver(RequestResult<CursorInfoData>::fromResult(Info));
1716+
// Handle literal expression.
1717+
if (auto *LitExpr = tryGetLiteralExpr(CursorInfo)) {
1718+
addCursorInfoForLiteral(Data, LitExpr, Lang, CompInvok,
1719+
CursorInfo->getLoc(), getPreviousASTSnaps());
1720+
}
1721+
1722+
if (Data.isEmpty()) {
1723+
Data.InternalDiagnostic =
1724+
"Resolved to incomplete expression or statement.";
1725+
}
1726+
1727+
Receiver(RequestResult<CursorInfoData>::fromResult(Data));
16481728
return;
16491729
}
16501730
case CursorInfoKind::Invalid:

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1955,7 +1955,8 @@ struct ResponseSymbolInfo {
19551955
}
19561956
OS << ")" << '\n';
19571957

1958-
OS << Name << '\n';
1958+
if (Name)
1959+
OS << Name << '\n';
19591960
if (USR)
19601961
OS << USR << '\n';
19611962
if (Lang)

0 commit comments

Comments
 (0)