Skip to content

Commit 6d94095

Browse files
author
Nathan Hawes
committed
[SourceKit][SymbolGraph] Add a 'ParentContexts' field the CursorInfo response
When the SymbolGraph json is requested via (key.retrieve_symbol_graph: 1) this adds a new field in the response that lists all the parent contexts of the symbol under the cursor with their symbol graph kind and name, and their USR: key.parent_contexts: [ { key.kind: "swift.struct", key.name: "Parent", key.usr: "s:27cursor_symbol_graph_parents6ParentV" }, ... ] } Resolves rdar://problem/73904365
1 parent e2bac38 commit 6d94095

File tree

11 files changed

+356
-71
lines changed

11 files changed

+356
-71
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===--- SymbolGraphPathComponent.h - Swift SymbolGraph Path Component ----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SYMBOLGRAPHGEN_PATHCOMPONENT_H
14+
#define SWIFT_SYMBOLGRAPHGEN_PATHCOMPONENT_H
15+
16+
#include "llvm/ADT/SmallString.h"
17+
18+
namespace swift {
19+
class ValueDecl;
20+
21+
namespace symbolgraphgen {
22+
23+
/// Summary information for a node along a path through a symbol graph.
24+
struct PathComponent {
25+
/// The title of the corresponding symbol graph node.
26+
SmallString<32> Title;
27+
/// The kind of the corresponding symbol graph node.
28+
StringRef Kind;
29+
/// The swift decl associated with the corresponding symbol graph node.
30+
const ValueDecl *VD;
31+
};
32+
33+
} // end namespace symbolgraphgen
34+
} // end namespace swift
35+
36+
#endif // SWIFT_SYMBOLGRAPHGEN_PATHCOMPONENT_H

include/swift/SymbolGraphGen/SymbolGraphGen.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Module.h"
1717
#include "swift/AST/Type.h"
1818
#include "SymbolGraphOptions.h"
19+
#include "PathComponent.h"
1920

2021
namespace swift {
2122
class ValueDecl;
@@ -25,14 +26,17 @@ namespace symbolgraphgen {
2526
/// Emit a Symbol Graph JSON file for a module.
2627
int emitSymbolGraphForModule(ModuleDecl *M, const SymbolGraphOptions &Options);
2728

28-
/// Print a Symbol Graph containing a single node for the given decl.
29+
/// Print a Symbol Graph containing a single node for the given decl to \p OS.
30+
/// The \p ParentContexts out parameter will also be populated with information
31+
/// about each parent context of the given decl, from outermost to innermost.
2932
///
30-
/// \returns \c EXIT_SUCCESS if the kind of the provided node is supported and
31-
/// its Symbo lGraph was printed, or \c EXIT_FAILURE otherwise.
33+
/// \returns \c EXIT_SUCCESS if the kind of the provided node is supported or
34+
/// \c EXIT_FAILURE otherwise.
3235
int printSymbolGraphForDecl(const ValueDecl *D, Type BaseTy,
33-
bool InSynthesizedExtensions,
34-
const SymbolGraphOptions &Options,
35-
llvm::raw_ostream &OS);
36+
bool InSynthesizedExtension,
37+
const SymbolGraphOptions &Options,
38+
llvm::raw_ostream &OS,
39+
SmallVectorImpl<PathComponent> &ParentContexts);
3640

3741
} // end namespace symbolgraphgen
3842
} // end namespace swift

lib/SymbolGraphGen/Symbol.cpp

+57-59
Original file line numberDiff line numberDiff line change
@@ -44,72 +44,58 @@ void Symbol::serializeKind(StringRef Identifier, StringRef DisplayName,
4444
});
4545
}
4646

47-
void Symbol::serializeKind(llvm::json::OStream &OS) const {
48-
// supportsKind and serializeKind must agree.
47+
std::pair<StringRef, StringRef> Symbol::getKind(const ValueDecl *VD) const {
48+
// Make sure supportsKind stays in sync with getKind.
4949
assert(Symbol::supportsKind(VD->getKind()) && "unsupported decl kind");
50-
51-
AttributeRAII A("kind", OS);
5250
switch (VD->getKind()) {
5351
case swift::DeclKind::Class:
54-
serializeKind("swift.class", "Class", OS);
55-
break;
52+
return {"swift.class", "Class"};
5653
case swift::DeclKind::Struct:
57-
serializeKind("swift.struct", "Structure", OS);
58-
break;
54+
return {"swift.struct", "Structure"};
5955
case swift::DeclKind::Enum:
60-
serializeKind("swift.enum", "Enumeration", OS);
61-
break;
56+
return {"swift.enum", "Enumeration"};
6257
case swift::DeclKind::EnumElement:
63-
serializeKind("swift.enum.case", "Case", OS);
64-
break;
58+
return {"swift.enum.case", "Case"};
6559
case swift::DeclKind::Protocol:
66-
serializeKind("swift.protocol", "Protocol", OS);
67-
break;
60+
return {"swift.protocol", "Protocol"};
6861
case swift::DeclKind::Constructor:
69-
serializeKind("swift.init", "Initializer", OS);
70-
break;
62+
return {"swift.init", "Initializer"};
7163
case swift::DeclKind::Destructor:
72-
serializeKind("swift.deinit", "Deinitializer", OS);
73-
break;
64+
return {"swift.deinit", "Deinitializer"};
7465
case swift::DeclKind::Func:
75-
if (VD->isOperator()) {
76-
serializeKind("swift.func.op", "Operator", OS);
77-
} else if (VD->isStatic()) {
78-
serializeKind("swift.type.method", "Type Method", OS);
79-
} else if (VD->getDeclContext()->getSelfNominalTypeDecl()){
80-
serializeKind("swift.method", "Instance Method", OS);
81-
} else {
82-
serializeKind("swift.func", "Function", OS);
83-
}
84-
break;
66+
if (VD->isOperator())
67+
return {"swift.func.op", "Operator"};
68+
if (VD->isStatic())
69+
return {"swift.type.method", "Type Method"};
70+
if (VD->getDeclContext()->getSelfNominalTypeDecl())
71+
return {"swift.method", "Instance Method"};
72+
return {"swift.func", "Function"};
8573
case swift::DeclKind::Var:
86-
if (VD->isStatic()) {
87-
serializeKind("swift.type.property", "Type Property", OS);
88-
} else if (VD->getDeclContext()->getSelfNominalTypeDecl()) {
89-
serializeKind("swift.property", "Instance Property", OS);
90-
} else {
91-
serializeKind("swift.var", "Global Variable", OS);
92-
}
93-
break;
74+
if (VD->isStatic())
75+
return {"swift.type.property", "Type Property"};
76+
if (VD->getDeclContext()->getSelfNominalTypeDecl())
77+
return {"swift.property", "Instance Property"};
78+
return {"swift.var", "Global Variable"};
9479
case swift::DeclKind::Subscript:
95-
if (VD->isStatic()) {
96-
serializeKind("swift.type.subscript", "Type Subscript", OS);
97-
} else {
98-
serializeKind("swift.subscript", "Instance Subscript", OS);
99-
}
100-
break;
80+
if (VD->isStatic())
81+
return {"swift.type.subscript", "Type Subscript"};
82+
return {"swift.subscript", "Instance Subscript"};
10183
case swift::DeclKind::TypeAlias:
102-
serializeKind("swift.typealias", "Type Alias", OS);
103-
break;
84+
return {"swift.typealias", "Type Alias"};
10485
case swift::DeclKind::AssociatedType:
105-
serializeKind("swift.associatedtype", "Associated Type", OS);
106-
break;
86+
return {"swift.associatedtype", "Associated Type"};
10787
default:
10888
llvm::errs() << "Unsupported kind: " << VD->getKindName(VD->getKind());
10989
llvm_unreachable("Unsupported declaration kind for symbol graph");
11090
}
11191
}
11292

93+
void Symbol::serializeKind(llvm::json::OStream &OS) const {
94+
AttributeRAII A("kind", OS);
95+
std::pair<StringRef, StringRef> IDAndName = getKind(VD);
96+
serializeKind(IDAndName.first, IDAndName.second, OS);
97+
}
98+
11399
void Symbol::serializeIdentifier(llvm::json::OStream &OS) const {
114100
OS.attributeObject("identifier", [&](){
115101
SmallString<256> USR;
@@ -121,17 +107,17 @@ void Symbol::serializeIdentifier(llvm::json::OStream &OS) const {
121107

122108
void Symbol::serializePathComponents(llvm::json::OStream &OS) const {
123109
OS.attributeArray("pathComponents", [&](){
124-
SmallVector<SmallString<32>, 8> PathComponents;
110+
SmallVector<PathComponent, 8> PathComponents;
125111
getPathComponents(PathComponents);
126112
for (auto Component : PathComponents) {
127-
OS.value(Component);
113+
OS.value(Component.Title);
128114
}
129115
});
130116
}
131117

132118
void Symbol::serializeNames(llvm::json::OStream &OS) const {
133119
OS.attributeObject("names", [&](){
134-
SmallVector<SmallString<32>, 8> PathComponents;
120+
SmallVector<PathComponent, 8> PathComponents;
135121
getPathComponents(PathComponents);
136122

137123
if (isa<GenericTypeDecl>(VD)) {
@@ -141,12 +127,12 @@ void Symbol::serializeNames(llvm::json::OStream &OS) const {
141127
if (It != PathComponents.begin()) {
142128
FullyQualifiedTitle.push_back('.');
143129
}
144-
FullyQualifiedTitle.append(*It);
130+
FullyQualifiedTitle.append(It->Title);
145131
}
146132

147133
OS.attribute("title", FullyQualifiedTitle.str());
148134
} else {
149-
OS.attribute("title", PathComponents.back());
135+
OS.attribute("title", PathComponents.back().Title);
150136
}
151137

152138
Graph->serializeNavigatorDeclarationFragments("navigator", *this, OS);
@@ -481,16 +467,27 @@ void Symbol::serialize(llvm::json::OStream &OS) const {
481467
}
482468

483469
void
484-
Symbol::getPathComponents(SmallVectorImpl<SmallString<32>> &Components) const {
470+
Symbol::getPathComponents(SmallVectorImpl<PathComponent> &Components) const {
471+
// Note: this is also used for sourcekit's cursor-info request, so can be
472+
// called on local symbols too. For such symbols, the path contains all parent
473+
// decl contexts that are currently representable in the symbol graph,
474+
// skipping over the rest (e.g. containing closures and accessors).
485475

486476
auto collectPathComponents = [&](const ValueDecl *Decl,
487-
SmallVectorImpl<SmallString<32>> &DeclComponents) {
488-
// Collect the spellings of the fully qualified identifier components.
477+
SmallVectorImpl<PathComponent> &DeclComponents) {
478+
// Collect the spellings, kinds, and decls of the fully qualified identifier
479+
// components.
489480
while (Decl && !isa<ModuleDecl>(Decl)) {
490481
SmallString<32> Scratch;
491482
Decl->getName().getString(Scratch);
492-
DeclComponents.push_back(Scratch);
493-
if (const auto *DC = Decl->getDeclContext()) {
483+
if (supportsKind(Decl->getKind()))
484+
DeclComponents.push_back({Scratch, getKind(Decl).first, Decl});
485+
486+
// Find the next parent.
487+
auto *DC = Decl->getDeclContext();
488+
while (DC && DC->getContextKind() == DeclContextKind::AbstractClosureExpr)
489+
DC = DC->getParent();
490+
if (DC) {
494491
if (const auto *Nominal = DC->getSelfNominalTypeDecl()) {
495492
Decl = Nominal;
496493
} else {
@@ -508,7 +505,8 @@ Symbol::getPathComponents(SmallVectorImpl<SmallString<32>> &Components) const {
508505
// a protocol. Build a path as if it were defined in the base type.
509506
SmallString<32> LastPathComponent;
510507
VD->getName().getString(LastPathComponent);
511-
Components.push_back(LastPathComponent);
508+
if (supportsKind(VD->getKind()))
509+
Components.push_back({LastPathComponent, getKind(VD).first, VD});
512510
collectPathComponents(BaseTypeDecl, Components);
513511
} else {
514512
// Otherwise, this is just a normal declaration, so we can build
@@ -521,13 +519,13 @@ Symbol::getPathComponents(SmallVectorImpl<SmallString<32>> &Components) const {
521519
}
522520

523521
void Symbol::printPath(llvm::raw_ostream &OS) const {
524-
SmallVector<SmallString<32>, 8> Components;
522+
SmallVector<PathComponent, 8> Components;
525523
getPathComponents(Components);
526524
for (auto it = Components.begin(); it != Components.end(); ++it) {
527525
if (it != Components.begin()) {
528526
OS << '.';
529527
}
530-
OS << it->str();
528+
OS << it->Title.str();
531529
}
532530
}
533531

lib/SymbolGraphGen/Symbol.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/Type.h"
1919
#include "swift/Basic/LLVM.h"
2020
#include "swift/Markup/Markup.h"
21+
#include "swift/SymbolGraphGen/PathComponent.h"
2122

2223
namespace swift {
2324
namespace symbolgraphgen {
@@ -34,6 +35,8 @@ class Symbol {
3435
Type BaseType;
3536
const NominalTypeDecl *SynthesizedBaseTypeDecl;
3637

38+
std::pair<StringRef, StringRef> getKind(const ValueDecl *VD) const;
39+
3740
void serializeKind(StringRef Identifier, StringRef DisplayName,
3841
llvm::json::OStream &OS) const;
3942

@@ -95,7 +98,7 @@ class Symbol {
9598
return SynthesizedBaseTypeDecl;
9699
}
97100

98-
void getPathComponents(SmallVectorImpl<SmallString<32>> &Components) const;
101+
void getPathComponents(SmallVectorImpl<PathComponent> &Components) const;
99102

100103
/// Print the symbol path to an output stream.
101104
void printPath(llvm::raw_ostream &OS) const;

lib/SymbolGraphGen/SymbolGraphGen.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ int symbolgraphgen::
104104
printSymbolGraphForDecl(const ValueDecl *D, Type BaseTy,
105105
bool InSynthesizedExtension,
106106
const SymbolGraphOptions &Options,
107-
llvm::raw_ostream &OS) {
107+
llvm::raw_ostream &OS,
108+
SmallVectorImpl<PathComponent> &ParentContexts) {
108109
if (!Symbol::supportsKind(D->getKind()))
109110
return EXIT_FAILURE;
110111

@@ -119,6 +120,11 @@ printSymbolGraphForDecl(const ValueDecl *D, Type BaseTy,
119120
: nullptr;
120121

121122
Symbol MySym(&Graph, D, NTD, BaseTy);
123+
124+
MySym.getPathComponents(ParentContexts);
125+
assert(!ParentContexts.empty() && "doesn't have node for MySym?");
126+
ParentContexts.pop_back();
127+
122128
Graph.recordNode(MySym);
123129
Graph.serialize(JOS);
124130
return EXIT_SUCCESS;

0 commit comments

Comments
 (0)