Skip to content

Commit 54f0fab

Browse files
committed
[IDE] Add TypeContextInfo callbacks to parser
TypeContextInfo is for new SourceKit request which receives source location, and returns context type and members which can be referenced by "implicit member expression" syntax. Implement that as a code completion callbacks.
1 parent cc1d5c1 commit 54f0fab

File tree

5 files changed

+505
-2
lines changed

5 files changed

+505
-2
lines changed

include/swift/IDE/TypeContextInfo.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===--- TypeContextInfo.h --------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2019 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_IDE_TYPECONTEXTINFO_H
14+
#define SWIFT_IDE_TYPECONTEXTINFO_H
15+
16+
#include "swift/AST/Type.h"
17+
#include "swift/Basic/LLVM.h"
18+
19+
namespace swift {
20+
class CodeCompletionCallbacksFactory;
21+
22+
namespace ide {
23+
24+
/// A result item for context info query.
25+
class TypeContextInfoItem {
26+
public:
27+
/// Possible expected type.
28+
Type ExpectedTy;
29+
/// Members of \c ExpectedTy which can be referenced by "Implicit Member
30+
/// Expression".
31+
SmallVector<ValueDecl *, 0> ImplicitMembers;
32+
33+
TypeContextInfoItem(Type ExpectedTy) : ExpectedTy(ExpectedTy) {}
34+
};
35+
36+
/// An abstract base class for consumers of context info results.
37+
class TypeContextInfoConsumer {
38+
public:
39+
virtual ~TypeContextInfoConsumer() {}
40+
virtual void handleResults(ArrayRef<TypeContextInfoItem>) = 0;
41+
};
42+
43+
/// Printing consumer
44+
class PrintingTypeContextInfoConsumer : public TypeContextInfoConsumer {
45+
llvm::raw_ostream &OS;
46+
47+
public:
48+
PrintingTypeContextInfoConsumer(llvm::raw_ostream &OS) : OS(OS) {}
49+
50+
void handleResults(ArrayRef<TypeContextInfoItem>) override;
51+
};
52+
53+
/// Create a factory for code completion callbacks.
54+
CodeCompletionCallbacksFactory *
55+
makeTypeContextInfoCallbacksFactory(TypeContextInfoConsumer &Consumer);
56+
57+
} // namespace ide
58+
} // namespace swift
59+
60+
#endif // SWIFT_IDE_TYPECONTEXTINFO_H

lib/IDE/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_swift_host_library(swiftIDE STATIC
1414
IDETypeChecking.cpp
1515
APIDigesterData.cpp
1616
SourceEntityWalker.cpp
17+
TypeContextInfo.cpp
1718
LINK_LIBRARIES
1819
swiftAST
1920
swiftFrontend

lib/IDE/TypeContextInfo.cpp

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
//===--- TypeContextInfo.cpp ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2019 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+
#include "swift/IDE/TypeContextInfo.h"
14+
#include "ExprContextAnalysis.h"
15+
#include "swift/AST/GenericEnvironment.h"
16+
#include "swift/AST/NameLookup.h"
17+
#include "swift/AST/USRGeneration.h"
18+
#include "swift/Parse/CodeCompletionCallbacks.h"
19+
#include "swift/Sema/IDETypeChecking.h"
20+
#include "clang/AST/Attr.h"
21+
#include "clang/AST/Decl.h"
22+
23+
using namespace swift;
24+
using namespace ide;
25+
26+
class ContextInfoCallbacks : public CodeCompletionCallbacks {
27+
TypeContextInfoConsumer &Consumer;
28+
SourceLoc Loc;
29+
Expr *ParsedExpr = nullptr;
30+
DeclContext *CurDeclContext = nullptr;
31+
32+
void getImplicitMembers(Type T, SmallVectorImpl<ValueDecl *> &Result);
33+
34+
public:
35+
ContextInfoCallbacks(Parser &P, TypeContextInfoConsumer &Consumer)
36+
: CodeCompletionCallbacks(P), Consumer(Consumer) {}
37+
38+
void completeExpr() override{};
39+
40+
// Ignore callbacks for suffix completions
41+
// {
42+
void completeDotExpr(Expr *E, SourceLoc DotLoc) override{};
43+
void completePostfixExpr(Expr *E, bool hasSpace) override{};
44+
void completeExprSuper(SuperRefExpr *SRE) override{};
45+
void completeExprSuperDot(SuperRefExpr *SRE) override{};
46+
// }
47+
48+
// Ignore non-expression callbacks.
49+
// {
50+
void completeInPrecedenceGroup(SyntaxKind SK) override{};
51+
void completePoundAvailablePlatform() override{};
52+
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override {}
53+
void completeTypeSimpleBeginning() override {}
54+
void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override {}
55+
void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override {}
56+
void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) override {}
57+
void completeDeclAttrParam(DeclAttrKind DK, int Index) override {}
58+
void completeNominalMemberBeginning(
59+
SmallVectorImpl<StringRef> &Keywords) override {}
60+
void completeImportDecl(
61+
std::vector<std::pair<Identifier, SourceLoc>> &Path) override {}
62+
void completeAfterPoundExpr(CodeCompletionExpr *E,
63+
Optional<StmtKind> ParentKind) override {}
64+
void completeAfterPoundDirective() override {}
65+
void completePlatformCondition() override {}
66+
void completeGenericParams(TypeLoc TL) override {}
67+
void completeAfterIfStmt(bool hasElse) override {}
68+
void completeAccessorBeginning() override{};
69+
// }
70+
71+
void completeStmtOrExpr() override{};
72+
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
73+
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
74+
void completeCaseStmtBeginning() override;
75+
76+
void completeAssignmentRHS(AssignExpr *E) override{};
77+
void completeCallArg(CodeCompletionExpr *E) override;
78+
void completeReturnStmt(CodeCompletionExpr *E) override;
79+
void completeYieldStmt(CodeCompletionExpr *E,
80+
Optional<unsigned> yieldIndex) override;
81+
82+
void completeUnresolvedMember(CodeCompletionExpr *E,
83+
SourceLoc DotLoc) override;
84+
void completeCaseStmtDotPrefix() override;
85+
86+
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override{};
87+
88+
void doneParsing() override;
89+
};
90+
91+
void ContextInfoCallbacks::completePostfixExprBeginning(CodeCompletionExpr *E) {
92+
CurDeclContext = P.CurDeclContext;
93+
ParsedExpr = E;
94+
}
95+
96+
void ContextInfoCallbacks::completeForEachSequenceBeginning(
97+
CodeCompletionExpr *E) {
98+
CurDeclContext = P.CurDeclContext;
99+
ParsedExpr = E;
100+
}
101+
void ContextInfoCallbacks::completeCallArg(CodeCompletionExpr *E) {
102+
CurDeclContext = P.CurDeclContext;
103+
ParsedExpr = E;
104+
}
105+
void ContextInfoCallbacks::completeReturnStmt(CodeCompletionExpr *E) {
106+
CurDeclContext = P.CurDeclContext;
107+
ParsedExpr = E;
108+
}
109+
void ContextInfoCallbacks::completeYieldStmt(CodeCompletionExpr *E,
110+
Optional<unsigned> yieldIndex) {
111+
CurDeclContext = P.CurDeclContext;
112+
ParsedExpr = E;
113+
}
114+
void ContextInfoCallbacks::completeUnresolvedMember(CodeCompletionExpr *E,
115+
SourceLoc DotLoc) {
116+
CurDeclContext = P.CurDeclContext;
117+
ParsedExpr = E;
118+
}
119+
120+
void ContextInfoCallbacks::completeCaseStmtBeginning() {
121+
// TODO: Implement?
122+
}
123+
void ContextInfoCallbacks::completeCaseStmtDotPrefix() {
124+
// TODO: Implement?
125+
}
126+
127+
void ContextInfoCallbacks::doneParsing() {
128+
if (!ParsedExpr)
129+
return;
130+
131+
typeCheckContextUntil(
132+
CurDeclContext,
133+
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
134+
135+
ExprContextInfo Info(CurDeclContext, ParsedExpr);
136+
137+
llvm::SmallSet<CanType, 2> seenTypes;
138+
SmallVector<TypeContextInfoItem, 2> results;
139+
140+
for (auto T : Info.getPossibleTypes()) {
141+
if (T->is<ErrorType>() || T->is<UnresolvedType>())
142+
continue;
143+
if (auto env = CurDeclContext->getGenericEnvironmentOfContext())
144+
T = env->mapTypeIntoContext(T);
145+
146+
// TODO: Do we need '.none' for Optionals?
147+
auto objT = T->lookThroughAllOptionalTypes();
148+
149+
if (!seenTypes.insert(objT->getCanonicalType()).second)
150+
continue;
151+
152+
results.emplace_back(T);
153+
auto &item = results.back();
154+
getImplicitMembers(objT, item.ImplicitMembers);
155+
}
156+
157+
Consumer.handleResults(results);
158+
}
159+
160+
void ContextInfoCallbacks::getImplicitMembers(
161+
Type T, SmallVectorImpl<ValueDecl *> &Result) {
162+
163+
if (!T->mayHaveMembers())
164+
return;
165+
166+
class LocalConsumer : public VisibleDeclConsumer {
167+
DeclContext *DC;
168+
LazyResolver *TypeResolver;
169+
ModuleDecl *CurModule;
170+
Type T;
171+
SmallVectorImpl<ValueDecl *> &Result;
172+
173+
bool canBeImplictMember(ValueDecl *VD) {
174+
if (VD->isOperator())
175+
return false;
176+
177+
if (!VD->hasInterfaceType()) {
178+
TypeResolver->resolveDeclSignature(VD);
179+
if (!VD->hasInterfaceType())
180+
return false;
181+
}
182+
183+
// Enum element decls can always be referenced by implicit member
184+
// expression.
185+
if (isa<EnumElementDecl>(VD))
186+
return true;
187+
188+
// Static properties which is convertible to 'Self'.
189+
if (isa<VarDecl>(VD) && VD->isStatic()) {
190+
auto declTy = T->getTypeOfMember(CurModule, VD);
191+
if (declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC))
192+
return true;
193+
}
194+
195+
return false;
196+
}
197+
198+
public:
199+
LocalConsumer(DeclContext *DC, Type T, SmallVectorImpl<ValueDecl *> &Result)
200+
: DC(DC), TypeResolver(DC->getASTContext().getLazyResolver()),
201+
CurModule(DC->getParentModule()), T(T), Result(Result) {}
202+
203+
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) {
204+
if (canBeImplictMember(VD) && !VD->shouldHideFromEditor())
205+
Result.push_back(VD);
206+
}
207+
208+
} LocalConsumer(CurDeclContext, T, Result);
209+
210+
lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext,
211+
CurDeclContext->getASTContext().getLazyResolver(),
212+
/*includeInstanceMembers=*/false);
213+
}
214+
215+
void PrintingTypeContextInfoConsumer::handleResults(
216+
ArrayRef<TypeContextInfoItem> results) {
217+
OS << "-----BEGIN TYPE CONTEXT INFO-----\n";
218+
for (auto resultItem : results) {
219+
OS << "- TypeName: ";
220+
resultItem.ExpectedTy.print(OS);
221+
OS << "\n";
222+
223+
OS << " TypeUSR: ";
224+
printTypeUSR(resultItem.ExpectedTy, OS);
225+
OS << "\n";
226+
227+
OS << " ImplicitMembers:";
228+
if (resultItem.ImplicitMembers.empty())
229+
OS << " []";
230+
OS << "\n";
231+
for (auto VD : resultItem.ImplicitMembers) {
232+
OS << " - ";
233+
234+
OS << "Name: ";
235+
VD->getFullName().print(OS);
236+
OS << "\n";
237+
238+
StringRef BriefDoc = VD->getBriefComment();
239+
if (!BriefDoc.empty()) {
240+
OS << " DocBrief: \"";
241+
OS << VD->getBriefComment();
242+
OS << "\"\n";
243+
}
244+
}
245+
}
246+
OS << "-----END TYPE CONTEXT INFO-----\n";
247+
}
248+
249+
CodeCompletionCallbacksFactory *swift::ide::makeTypeContextInfoCallbacksFactory(
250+
TypeContextInfoConsumer &Consumer) {
251+
252+
// CC callback factory which produces 'ContextInfoCallbacks'.
253+
class ContextInfoCallbacksFactoryImpl
254+
: public CodeCompletionCallbacksFactory {
255+
TypeContextInfoConsumer &Consumer;
256+
257+
public:
258+
ContextInfoCallbacksFactoryImpl(TypeContextInfoConsumer &Consumer)
259+
: Consumer(Consumer) {}
260+
261+
CodeCompletionCallbacks *createCodeCompletionCallbacks(Parser &P) override {
262+
return new ContextInfoCallbacks(P, Consumer);
263+
}
264+
};
265+
266+
return new ContextInfoCallbacksFactoryImpl(Consumer);
267+
}

0 commit comments

Comments
 (0)