Skip to content

Commit 9b8fb7d

Browse files
author
Nathan Hawes
committed
[CodeCompletion] Rename a few types/methods for clarity plus other small refactorings (NFC)
Also put subclasses of TypeCheckCompletionCallback into their own header.
1 parent ee660c6 commit 9b8fb7d

File tree

9 files changed

+116
-90
lines changed

9 files changed

+116
-90
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ namespace swift {
122122
class IndexSubset;
123123
struct SILAutoDiffDerivativeFunctionKey;
124124
struct InterfaceSubContextDelegate;
125-
class CompletionCollector;
125+
class TypeCheckCompletionCallback;
126126

127127
enum class KnownProtocolKind : uint8_t;
128128

@@ -253,7 +253,7 @@ class ASTContext final {
253253
/// Diags - The diagnostics engine.
254254
DiagnosticEngine &Diags;
255255

256-
CompletionCollector *CompletionCallback = nullptr;
256+
TypeCheckCompletionCallback *CompletionCallback = nullptr;
257257

258258
/// The request-evaluator that is used to process various requests.
259259
Evaluator evaluator;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
3+
// Licensed under Apache License v2.0 with Runtime Library Exception
4+
//
5+
// See https://swift.org/LICENSE.txt for license information
6+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
/// \file
11+
/// Provides TypeCheckCompletionCallback implementations for the various kinds
12+
/// of code completion. These extract and persist information needed to compute
13+
/// completion results from the solutions formed during expression typechecking.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SEMA_CODECOMPLETIONTYPECHECKING_H
18+
#define SWIFT_SEMA_CODECOMPLETIONTYPECHECKING_H
19+
20+
namespace swift {
21+
class Decl;
22+
class DeclContext;
23+
class Type;
24+
class ValueDecl;
25+
class CodeCompletionExpr;
26+
27+
namespace constraints {
28+
class Solution;
29+
}
30+
31+
class TypeCheckCompletionCallback {
32+
public:
33+
/// Called for each solution produced while type-checking an expression
34+
/// containing a code completion expression.
35+
virtual void sawSolution(const constraints::Solution &solution) = 0;
36+
virtual ~TypeCheckCompletionCallback() {}
37+
};
38+
39+
40+
/// Used to collect and store information needed to perform member completion
41+
/// (\c CompletionKind::DotExpr ) from the solutions formed during expression
42+
/// type-checking.
43+
class DotExprTypeCheckCompletionCallback: public TypeCheckCompletionCallback {
44+
public:
45+
struct Result {
46+
Type BaseTy;
47+
ValueDecl* BaseDecl;
48+
SmallVector<Type, 4> ExpectedTypes;
49+
bool ExpectsNonVoid;
50+
bool BaseIsStaticMetaType;
51+
bool IsSingleExpressionBody;
52+
};
53+
54+
private:
55+
DeclContext *DC;
56+
CodeCompletionExpr *CompletionExpr;
57+
SmallVector<Result, 4> Results;
58+
llvm::DenseMap<std::pair<Type, Decl*>, size_t> BaseToSolutionIdx;
59+
bool GotCallback = false;
60+
61+
public:
62+
DotExprTypeCheckCompletionCallback(DeclContext *DC,
63+
CodeCompletionExpr *CompletionExpr)
64+
: DC(DC), CompletionExpr(CompletionExpr) {}
65+
66+
/// Get the results collected from any sawSolutions() callbacks recevied so
67+
/// far.
68+
ArrayRef<Result> getResults() const { return Results; }
69+
70+
/// True if at least one solution was passed via the \c sawSolution
71+
/// callback.
72+
bool gotCallback() const { return GotCallback; }
73+
74+
/// Typecheck the code completion expression in isolation, calling
75+
/// \c sawSolution for each solution formed.
76+
void fallbackTypeCheck();
77+
78+
void sawSolution(const constraints::Solution &solution) override;
79+
};
80+
}
81+
82+
#endif

include/swift/Sema/IDETypeChecking.h

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -44,64 +44,6 @@ namespace swift {
4444
class Type;
4545
class ValueDecl;
4646
struct PrintOptions;
47-
class CodeCompletionExpr;
48-
49-
namespace constraints {
50-
class Solution;
51-
}
52-
53-
namespace ide {
54-
class CodeCompletionContext;
55-
class CodeCompletionConsumer;
56-
}
57-
58-
class CompletionCollector {
59-
public:
60-
virtual void sawSolution(const constraints::Solution &solution) = 0;
61-
virtual ~CompletionCollector() {}
62-
};
63-
64-
65-
class DotExprLookup: public CompletionCollector {
66-
struct SolutionInfo {
67-
Type BaseTy;
68-
ValueDecl* BaseDecl;
69-
SmallVector<Type, 4> ExpectedTypes;
70-
bool ExpectsNonVoid;
71-
bool BaseIsStaticMetaType;
72-
bool IsSingleExpressionBody;
73-
};
74-
75-
SourceLoc DotLoc;
76-
DeclContext *DC;
77-
CodeCompletionExpr *CompletionExpr;
78-
SmallVector<SolutionInfo, 4> Solutions;
79-
llvm::DenseMap<std::pair<Type, Decl*>, size_t> BaseToSolutionIdx;
80-
bool GotCallback = false;
81-
82-
public:
83-
DotExprLookup(SourceLoc DotLoc, DeclContext *DC,
84-
CodeCompletionExpr *CompletionExpr)
85-
: DotLoc(DotLoc), DC(DC), CompletionExpr(CompletionExpr) {}
86-
87-
/// Lookup the completion members on the base expressions extracted from the
88-
/// solutions seen so far and pass them to the given \c Consumer.
89-
void performLookup(ide::CodeCompletionContext &CompletionCtx,
90-
ide::CodeCompletionConsumer &Consumer,
91-
bool isInSelector) const;
92-
93-
/// True if a solution was passed via the \c sawSolution callback.
94-
bool gotCallback() const { return GotCallback; }
95-
96-
/// Typecheck the code completion expression in isolation, calling
97-
/// \c sawSolution for each solution formed.
98-
void fallbackTypeCheck();
99-
100-
private:
101-
/// Called for each solution produced while type-checking an expression containing a code
102-
/// completion expression.
103-
void sawSolution(const constraints::Solution &solution) override;
104-
};
10547

10648
/// Typecheck binding initializer at \p bindingIndex.
10749
void typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned bindingIndex);

lib/IDE/CodeCompletion.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "swift/IDE/Utils.h"
3636
#include "swift/Parse/CodeCompletionCallbacks.h"
3737
#include "swift/Sema/IDETypeChecking.h"
38+
#include "swift/Sema/CodeCompletionTypeChecking.h"
3839
#include "swift/Syntax/SyntaxKind.h"
3940
#include "swift/Strings.h"
4041
#include "swift/Subsystems.h"
@@ -5911,17 +5912,18 @@ static void deliverCompletionResults(CodeCompletionContext &CompletionContext,
59115912
DCForModules);
59125913
}
59135914

5914-
void DotExprLookup::performLookup(ide::CodeCompletionContext &CompletionCtx,
5915-
CodeCompletionConsumer &Consumer,
5916-
bool IsInSelector) const {
5915+
void deliverDotExprResults(
5916+
ArrayRef<DotExprTypeCheckCompletionCallback::Result> Solutions,
5917+
Expr *BaseExpr, DeclContext *DC, SourceLoc DotLoc, bool IsInSelector,
5918+
ide::CodeCompletionContext &CompletionCtx,
5919+
CodeCompletionConsumer &Consumer) {
59175920
ASTContext &Ctx = DC->getASTContext();
59185921
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
59195922
&CompletionCtx);
59205923

59215924
if (DotLoc.isValid())
59225925
Lookup.setHaveDot(DotLoc);
59235926

5924-
Expr *BaseExpr = CompletionExpr->getBase();
59255927
Lookup.setIsSuperRefExpr(isa<SuperRefExpr>(BaseExpr));
59265928

59275929
if (auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
@@ -5980,21 +5982,26 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion() {
59805982
assert(CodeCompleteTokenExpr);
59815983
assert(CurDeclContext);
59825984

5983-
DotExprLookup Lookup(DotLoc, CurDeclContext, CodeCompleteTokenExpr);
5984-
llvm::SaveAndRestore<CompletionCollector*>
5985+
DotExprTypeCheckCompletionCallback Lookup(CurDeclContext,
5986+
CodeCompleteTokenExpr);
5987+
llvm::SaveAndRestore<TypeCheckCompletionCallback*>
59855988
CompletionCollector(Context.CompletionCallback, &Lookup);
59865989
typeCheckContextAt(CurDeclContext, CompletionLoc);
59875990

59885991
// This (hopefully) only happens in cases where the expression isn't
59895992
// typechecked during normal compilation either (e.g. member completion in a
5990-
// switch case where there switched value is invalid). Having normal
5993+
// switch case where there control expression is invalid). Having normal
59915994
// typechecking still resolve even these cases would be beneficial for
59925995
// tooling in general though.
59935996
if (!Lookup.gotCallback())
59945997
Lookup.fallbackTypeCheck();
59955998

59965999
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);
5997-
Lookup.performLookup(CompletionContext, Consumer, isInsideObjCSelector());
6000+
6001+
Expr *CheckedBase = CodeCompleteTokenExpr->getBase();
6002+
deliverDotExprResults(Lookup.getResults(), CheckedBase, CurDeclContext,
6003+
DotLoc, isInsideObjCSelector(), CompletionContext,
6004+
Consumer);
59986005
return true;
59996006
}
60006007
default:

lib/IDE/ExprContextAnalysis.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ namespace swift {
2222
class DeclContext;
2323
class Expr;
2424
class ValueDecl;
25-
class CompletionCollector;
2625

2726
namespace ide {
2827
enum class SemanticContextKind;

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "swift/Basic/STLExtras.h"
4242
#include "swift/Parse/Lexer.h"
4343
#include "swift/Sema/IDETypeChecking.h"
44+
#include "swift/Sema/CodeCompletionTypeChecking.h"
4445
#include "swift/Strings.h"
4546
#include "llvm/ADT/DenseMap.h"
4647
#include "llvm/ADT/PointerUnion.h"
@@ -865,7 +866,13 @@ bool TypeChecker::typeCheckForCodeCompletion(
865866
/*contextualType=*/Type(),
866867
/*isDiscarded=*/true);
867868

868-
(void)solveForCodeCompletion(completionTarget);
869+
switch (solveForCodeCompletion(completionTarget)) {
870+
case CompletionResult::Ok:
871+
case CompletionResult::Fallback:
872+
break;
873+
case CompletionResult::NotApplicable:
874+
llvm_unreachable("solve on CodeCompletionExpr produced not applicable?");
875+
}
869876
}
870877
return true;
871878
}
@@ -966,15 +973,16 @@ swift::lookupSemanticMember(DeclContext *DC, Type ty, DeclName name) {
966973
return TypeChecker::lookupMember(DC, ty, DeclNameRef(name), None);
967974
}
968975

969-
void DotExprLookup::fallbackTypeCheck() {
976+
void DotExprTypeCheckCompletionCallback::fallbackTypeCheck() {
970977
assert(!gotCallback());
971978
SolutionApplicationTarget completionTarget(CompletionExpr, DC, CTP_Unused,
972979
Type(), /*isDiscared=*/true);
973980
TypeChecker::typeCheckForCodeCompletion(
974981
completionTarget, [&](const Solution &S) { sawSolution(S); });
975982
}
976983

977-
void DotExprLookup::sawSolution(const constraints::Solution &S) {
984+
void DotExprTypeCheckCompletionCallback::
985+
sawSolution(const constraints::Solution &S) {
978986
GotCallback = true;
979987
auto &CS = S.getConstraintSystem();
980988

@@ -1047,9 +1055,9 @@ void DotExprLookup::sawSolution(const constraints::Solution &S) {
10471055
ReferencedDecl = SelectedOverload->choice.getDeclOrNull();
10481056

10491057
auto Key = std::make_pair(BaseTy, ReferencedDecl);
1050-
auto Ret = BaseToSolutionIdx.insert({Key, Solutions.size()});
1058+
auto Ret = BaseToSolutionIdx.insert({Key, Results.size()});
10511059
if (!Ret.second && ExpectedTy) {
1052-
Solutions[Ret.first->getSecond()].ExpectedTypes.push_back(ExpectedTy);
1060+
Results[Ret.first->getSecond()].ExpectedTypes.push_back(ExpectedTy);
10531061
} else {
10541062
bool ISDMT = S.isStaticallyDerivedMetatype(ParsedExpr);
10551063
bool SingleExprBody = false;
@@ -1070,9 +1078,9 @@ void DotExprLookup::sawSolution(const constraints::Solution &S) {
10701078
}
10711079
}
10721080

1073-
Solutions.push_back(
1081+
Results.push_back(
10741082
{BaseTy, ReferencedDecl, {}, DisallowVoid, ISDMT, SingleExprBody});
10751083
if (ExpectedTy)
1076-
Solutions.back().ExpectedTypes.push_back(ExpectedTy);
1084+
Results.back().ExpectedTypes.push_back(ExpectedTy);
10771085
}
10781086
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include "swift/Basic/Statistic.h"
4040
#include "swift/Parse/Confusables.h"
4141
#include "swift/Parse/Lexer.h"
42-
#include "swift/Sema/IDETypeChecking.h"
42+
#include "swift/Sema/CodeCompletionTypeChecking.h"
4343
#include "llvm/ADT/APInt.h"
4444
#include "llvm/ADT/DenseMap.h"
4545
#include "llvm/ADT/FoldingSet.h"

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class TypeResolution;
4242
class TypeResolutionOptions;
4343
class TypoCorrectionResults;
4444
class ExprPattern;
45-
class CompletionCollector;
4645
enum class TypeResolutionStage : uint8_t;
4746

4847
namespace constraints {

test/IDE/complete_enum_elements.swift

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
// RUN: %FileCheck %s -check-prefix=QUX_ENUM_NO_DOT < %t.enum.txt
5858

5959
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ENUM_QUAL_DOT_1 > %t.enum.txt
60-
// RUN: %FileCheck %s -check-prefix=FOO_ENUM_DOT_INVALID < %t.enum.txt
60+
// RUN: %FileCheck %s -check-prefix=FOO_ENUM_DOT < %t.enum.txt
6161

6262
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ENUM_QUAL_DOT_2 > %t.enum.txt
6363
// RUN: %FileCheck %s -check-prefix=BAR_ENUM_DOT < %t.enum.txt
@@ -127,17 +127,6 @@ enum FooEnum: CaseIterable {
127127
// FOO_ENUM_DOT_CONTEXT-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}}
128128
// FOO_ENUM_DOT_CONTEXT-NEXT: End completions
129129

130-
// FOO_ENUM_DOT_INVALID: Begin completions
131-
// FOO_ENUM_DOT_INVALID-NEXT: Keyword[self]/CurrNominal: self[#FooEnum.Type#]; name=self
132-
// FOO_ENUM_DOT_INVALID-NEXT: Keyword/CurrNominal: Type[#FooEnum.Type#]; name=Type
133-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[EnumElement]/CurrNominal: Foo1[#FooEnum#]{{; name=.+$}}
134-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[EnumElement]/CurrNominal: Foo2[#FooEnum#]{{; name=.+$}}
135-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: alias1[#FooEnum#]{{; name=.+$}}
136-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[InstanceMethod]/CurrNominal: hash({#(self): FooEnum#})[#(into: inout Hasher) -> Void#]{{; name=.+$}}
137-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[TypeAlias]/CurrNominal: AllCases[#[FooEnum]#]{{; name=.+$}}
138-
// FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}}
139-
// FOO_ENUM_DOT_INVALID-NEXT: End completions
140-
141130
// FOO_ENUM_DOT_ELEMENTS: Begin completions, 13 items
142131
// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo1[#FooEnum#]{{; name=.+$}}
143132
// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo2[#FooEnum#]{{; name=.+$}}

0 commit comments

Comments
 (0)