Skip to content

Commit 8340abd

Browse files
committed
[CodeCompletion] Move solver-based key path completion to its own file
1 parent c8aba81 commit 8340abd

File tree

6 files changed

+152
-101
lines changed

6 files changed

+152
-101
lines changed

include/swift/IDE/KeyPathCompletion.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===--- KeyPathCompletion.h ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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_KEYPATHCOMPLETION_H
14+
#define SWIFT_IDE_KEYPATHCOMPLETION_H
15+
16+
#include "swift/IDE/CodeCompletionConsumer.h"
17+
#include "swift/IDE/CodeCompletionContext.h"
18+
#include "swift/Sema/CodeCompletionTypeChecking.h"
19+
20+
namespace swift {
21+
namespace ide {
22+
23+
class KeyPathTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
24+
public:
25+
struct Result {
26+
/// The type on which completion should occur, i.e. a result type of the
27+
/// previous component.
28+
Type BaseType;
29+
/// Whether code completion happens on the key path's root.
30+
bool OnRoot;
31+
};
32+
33+
private:
34+
KeyPathExpr *KeyPath;
35+
SmallVector<Result, 4> Results;
36+
37+
public:
38+
KeyPathTypeCheckCompletionCallback(KeyPathExpr *KeyPath) : KeyPath(KeyPath) {}
39+
40+
ArrayRef<Result> getResults() const { return Results; }
41+
42+
void sawSolution(const constraints::Solution &solution) override;
43+
};
44+
45+
void deliverKeyPathResults(
46+
ArrayRef<KeyPathTypeCheckCompletionCallback::Result> Results,
47+
DeclContext *DC, SourceLoc DotLoc,
48+
ide::CodeCompletionContext &CompletionCtx,
49+
CodeCompletionConsumer &Consumer);
50+
51+
} // end namespace ide
52+
} // end namespace swift
53+
54+
#endif // SWIFT_IDE_KEYPATHCOMPLETION_H

include/swift/Sema/CodeCompletionTypeChecking.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,6 @@ namespace swift {
4242
virtual void sawSolution(const constraints::Solution &solution) = 0;
4343
virtual ~TypeCheckCompletionCallback() {}
4444
};
45-
46-
47-
class KeyPathTypeCheckCompletionCallback
48-
: public TypeCheckCompletionCallback {
49-
public:
50-
struct Result {
51-
/// The type on which completion should occur, i.e. a result type of the
52-
/// previous component.
53-
Type BaseType;
54-
/// Whether code completion happens on the key path's root.
55-
bool OnRoot;
56-
};
57-
58-
private:
59-
KeyPathExpr *KeyPath;
60-
SmallVector<Result, 4> Results;
61-
62-
public:
63-
KeyPathTypeCheckCompletionCallback(KeyPathExpr *KeyPath)
64-
: KeyPath(KeyPath) {}
65-
66-
ArrayRef<Result> getResults() const { return Results; }
67-
68-
void sawSolution(const constraints::Solution &solution) override;
69-
};
7045
}
7146

7247
#endif

lib/IDE/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_swift_host_library(swiftIDE STATIC
2323
Formatting.cpp
2424
FuzzyStringMatcher.cpp
2525
Refactoring.cpp
26+
KeyPathCompletion.cpp
2627
ModuleInterfacePrinting.cpp
2728
REPLCodeCompletion.cpp
2829
SwiftSourceDocInfo.cpp

lib/IDE/CodeCompletion.cpp

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "swift/IDE/CompletionLookup.h"
4040
#include "swift/IDE/CompletionOverrideLookup.h"
4141
#include "swift/IDE/DotExprCompletion.h"
42+
#include "swift/IDE/KeyPathCompletion.h"
4243
#include "swift/IDE/UnresolvedMemberCompletion.h"
4344
#include "swift/IDE/Utils.h"
4445
#include "swift/Parse/CodeCompletionCallbacks.h"
@@ -1320,28 +1321,6 @@ void swift::ide::deliverCompletionResults(
13201321
Consumer.handleResultsAndModules(CompletionContext, RequestedModules, DC);
13211322
}
13221323

1323-
void deliverKeyPathResults(
1324-
ArrayRef<KeyPathTypeCheckCompletionCallback::Result> Results,
1325-
DeclContext *DC, SourceLoc DotLoc,
1326-
ide::CodeCompletionContext &CompletionCtx,
1327-
CodeCompletionConsumer &Consumer) {
1328-
ASTContext &Ctx = DC->getASTContext();
1329-
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
1330-
&CompletionCtx);
1331-
1332-
if (DotLoc.isValid()) {
1333-
Lookup.setHaveDot(DotLoc);
1334-
}
1335-
Lookup.shouldCheckForDuplicates(Results.size() > 1);
1336-
1337-
for (auto &Result : Results) {
1338-
Lookup.setIsSwiftKeyPathExpr(Result.OnRoot);
1339-
Lookup.getValueExprCompletions(Result.BaseType);
1340-
}
1341-
1342-
deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);
1343-
}
1344-
13451324
bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
13461325
assert(ParsedExpr || CurDeclContext);
13471326

lib/IDE/KeyPathCompletion.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//===--- KeyPathCompletion.cpp --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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/KeyPathCompletion.h"
14+
#include "swift/IDE/CodeCompletion.h"
15+
#include "swift/IDE/CompletionLookup.h"
16+
#include "swift/Sema/ConstraintSystem.h"
17+
18+
using namespace swift;
19+
using namespace swift::constraints;
20+
using namespace swift::ide;
21+
22+
void KeyPathTypeCheckCompletionCallback::sawSolution(
23+
const constraints::Solution &S) {
24+
// Determine the code completion.
25+
size_t ComponentIndex = 0;
26+
for (auto &Component : KeyPath->getComponents()) {
27+
if (Component.getKind() == KeyPathExpr::Component::Kind::CodeCompletion) {
28+
break;
29+
} else {
30+
ComponentIndex++;
31+
}
32+
}
33+
assert(ComponentIndex < KeyPath->getComponents().size() &&
34+
"Didn't find a code compleiton component?");
35+
36+
Type BaseType;
37+
if (ComponentIndex == 0) {
38+
// We are completing on the root and need to extract the key path's root
39+
// type.
40+
if (KeyPath->getRootType()) {
41+
BaseType = S.getResolvedType(KeyPath->getRootType());
42+
} else {
43+
// The key path doesn't have a root TypeRepr set, so we can't look the key
44+
// path's root up through it. Build a constraint locator and look the
45+
// root type up through it.
46+
// FIXME: Improve the linear search over S.typeBindings when it's possible
47+
// to look up type variables by their locators.
48+
auto RootLocator =
49+
S.getConstraintLocator(KeyPath, {ConstraintLocator::KeyPathRoot});
50+
auto BaseVariableTypeBinding =
51+
llvm::find_if(S.typeBindings, [&RootLocator](const auto &Entry) {
52+
return Entry.first->getImpl().getLocator() == RootLocator;
53+
});
54+
if (BaseVariableTypeBinding != S.typeBindings.end()) {
55+
BaseType = S.simplifyType(BaseVariableTypeBinding->getSecond());
56+
}
57+
}
58+
} else {
59+
// We are completing after a component. Get the previous component's result
60+
// type.
61+
BaseType = S.simplifyType(S.getType(KeyPath, ComponentIndex - 1));
62+
}
63+
if (BaseType.isNull()) {
64+
return;
65+
}
66+
67+
// If ExpectedTy is a duplicate of any other result, ignore this solution.
68+
if (llvm::any_of(Results, [&](const Result &R) {
69+
return R.BaseType->isEqual(BaseType);
70+
})) {
71+
return;
72+
}
73+
Results.push_back({BaseType, /*OnRoot=*/(ComponentIndex == 0)});
74+
}
75+
76+
void swift::ide::deliverKeyPathResults(
77+
ArrayRef<KeyPathTypeCheckCompletionCallback::Result> Results,
78+
DeclContext *DC, SourceLoc DotLoc,
79+
ide::CodeCompletionContext &CompletionCtx,
80+
CodeCompletionConsumer &Consumer) {
81+
ASTContext &Ctx = DC->getASTContext();
82+
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
83+
&CompletionCtx);
84+
85+
if (DotLoc.isValid()) {
86+
Lookup.setHaveDot(DotLoc);
87+
}
88+
Lookup.shouldCheckForDuplicates(Results.size() > 1);
89+
90+
for (auto &Result : Results) {
91+
Lookup.setIsSwiftKeyPathExpr(Result.OnRoot);
92+
Lookup.getValueExprCompletions(Result.BaseType);
93+
}
94+
95+
deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);
96+
}

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -850,57 +850,3 @@ bool swift::isImplicitSingleExpressionReturn(ConstraintSystem &CS,
850850
}
851851
return false;
852852
}
853-
854-
void KeyPathTypeCheckCompletionCallback::sawSolution(
855-
const constraints::Solution &S) {
856-
// Determine the code completion.
857-
size_t ComponentIndex = 0;
858-
for (auto &Component : KeyPath->getComponents()) {
859-
if (Component.getKind() == KeyPathExpr::Component::Kind::CodeCompletion) {
860-
break;
861-
} else {
862-
ComponentIndex++;
863-
}
864-
}
865-
assert(ComponentIndex < KeyPath->getComponents().size() &&
866-
"Didn't find a code compleiton component?");
867-
868-
Type BaseType;
869-
if (ComponentIndex == 0) {
870-
// We are completing on the root and need to extract the key path's root
871-
// type.
872-
if (KeyPath->getRootType()) {
873-
BaseType = S.getResolvedType(KeyPath->getRootType());
874-
} else {
875-
// The key path doesn't have a root TypeRepr set, so we can't look the key
876-
// path's root up through it. Build a constraint locator and look the
877-
// root type up through it.
878-
// FIXME: Improve the linear search over S.typeBindings when it's possible
879-
// to look up type variables by their locators.
880-
auto RootLocator =
881-
S.getConstraintLocator(KeyPath, {ConstraintLocator::KeyPathRoot});
882-
auto BaseVariableTypeBinding =
883-
llvm::find_if(S.typeBindings, [&RootLocator](const auto &Entry) {
884-
return Entry.first->getImpl().getLocator() == RootLocator;
885-
});
886-
if (BaseVariableTypeBinding != S.typeBindings.end()) {
887-
BaseType = S.simplifyType(BaseVariableTypeBinding->getSecond());
888-
}
889-
}
890-
} else {
891-
// We are completing after a component. Get the previous component's result
892-
// type.
893-
BaseType = S.simplifyType(S.getType(KeyPath, ComponentIndex - 1));
894-
}
895-
if (BaseType.isNull()) {
896-
return;
897-
}
898-
899-
// If ExpectedTy is a duplicate of any other result, ignore this solution.
900-
if (llvm::any_of(Results, [&](const Result &R) {
901-
return R.BaseType->isEqual(BaseType);
902-
})) {
903-
return;
904-
}
905-
Results.push_back({BaseType, /*OnRoot=*/(ComponentIndex == 0)});
906-
}

0 commit comments

Comments
 (0)