mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CodeComplete] Perform function name lookup to complete unresolved members.
For completing unresolved members, if constraint solver does not have solutions, we look up the function names appearing in the same line of the code completion tokens, and use their parameters that are of enum/optionset type to deliver the code completion results. Swift SVN r31256
This commit is contained in:
@@ -696,6 +696,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
UnresolvedMemberExpr *UnresolvedExpr;
|
UnresolvedMemberExpr *UnresolvedExpr;
|
||||||
|
std::vector<std::string> TokensBeforeUnresolvedExpr;
|
||||||
CompletionKind Kind = CompletionKind::None;
|
CompletionKind Kind = CompletionKind::None;
|
||||||
Expr *ParsedExpr = nullptr;
|
Expr *ParsedExpr = nullptr;
|
||||||
SourceLoc DotLoc;
|
SourceLoc DotLoc;
|
||||||
@@ -2114,6 +2115,63 @@ public:
|
|||||||
RequestedCachedResults = RequestedResultsTy::toplevelResults();
|
RequestedCachedResults = RequestedResultsTy::toplevelResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LookupFuncByName : public swift::VisibleDeclConsumer {
|
||||||
|
CompletionLookup &Lookup;
|
||||||
|
std::vector<std::string> &SortedFuncNames;
|
||||||
|
llvm::SmallPtrSet<Decl*, 3> HandledDecls;
|
||||||
|
|
||||||
|
bool isNameHit(StringRef Name) {
|
||||||
|
return std::binary_search(SortedFuncNames.begin(), SortedFuncNames.end(),
|
||||||
|
Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void collectFuncTypes(FuncDecl *FD) {
|
||||||
|
if (isNameHit(FD->getNameStr()) && FD->getType() &&
|
||||||
|
FD-> getType()->is<FunctionType>()) {
|
||||||
|
unboxType(FD->getType()->getAs<FunctionType>()->getInput());
|
||||||
|
unboxType(FD->getType()->getAs<FunctionType>()->getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unboxType(Type T) {
|
||||||
|
if (T->getKind() == TypeKind::Paren) {
|
||||||
|
unboxType(T->getDesugaredType());
|
||||||
|
} else if (T->getKind() == TypeKind::Tuple) {
|
||||||
|
for (auto Ele : T->getAs<TupleType>()->getElements()) {
|
||||||
|
unboxType(Ele.getType());
|
||||||
|
}
|
||||||
|
} else if (auto NTD = T->getNominalOrBoundGenericNominal()){
|
||||||
|
if (HandledDecls.count(NTD) == 0) {
|
||||||
|
auto Reason = DeclVisibilityKind::MemberOfCurrentNominal;
|
||||||
|
if (!Lookup.handleEnumElement(NTD, Reason)) {
|
||||||
|
Lookup.handleOptionSetType(NTD, Reason);
|
||||||
|
}
|
||||||
|
HandledDecls.insert(NTD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
LookupFuncByName(CompletionLookup &Lookup,
|
||||||
|
std::vector<std::string> &SortedFuncNames) :
|
||||||
|
Lookup(Lookup), SortedFuncNames(SortedFuncNames) {
|
||||||
|
std::sort(SortedFuncNames.begin(), SortedFuncNames.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
|
||||||
|
if (auto FD = dyn_cast<FuncDecl>(VD)) {
|
||||||
|
collectFuncTypes(FD);
|
||||||
|
}
|
||||||
|
if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) {
|
||||||
|
for (auto M : NTD->getMembers()) {
|
||||||
|
if (auto FD = dyn_cast<FuncDecl>(M)) {
|
||||||
|
collectFuncTypes(FD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void getUnresolvedMemberCompletions(SourceLoc Loc, SmallVectorImpl<Type> &Types) {
|
void getUnresolvedMemberCompletions(SourceLoc Loc, SmallVectorImpl<Type> &Types) {
|
||||||
NeedLeadingDot = !HaveDot;
|
NeedLeadingDot = !HaveDot;
|
||||||
for (auto T : Types) {
|
for (auto T : Types) {
|
||||||
@@ -2126,6 +2184,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getUnresolvedMemberCompletions(SourceLoc Loc,
|
||||||
|
std::vector<std::string> &FuncNames) {
|
||||||
|
NeedLeadingDot = !HaveDot;
|
||||||
|
LookupFuncByName Lookup(*this, FuncNames);
|
||||||
|
lookupVisibleDecls(Lookup, CurrDeclContext, TypeResolver.get(), true);
|
||||||
|
}
|
||||||
|
|
||||||
void getTypeContextEnumElementCompletions(SourceLoc Loc) {
|
void getTypeContextEnumElementCompletions(SourceLoc Loc) {
|
||||||
llvm::SaveAndRestore<LookupKind> ChangeLookupKind(
|
llvm::SaveAndRestore<LookupKind> ChangeLookupKind(
|
||||||
Kind, LookupKind::EnumElement);
|
Kind, LookupKind::EnumElement);
|
||||||
@@ -2565,6 +2630,9 @@ void CodeCompletionCallbacksImpl::completeUnresolvedMember(UnresolvedMemberExpr
|
|||||||
Kind = CompletionKind::UnresolvedMember;
|
Kind = CompletionKind::UnresolvedMember;
|
||||||
CurDeclContext = P.CurDeclContext;
|
CurDeclContext = P.CurDeclContext;
|
||||||
UnresolvedExpr = E;
|
UnresolvedExpr = E;
|
||||||
|
for (auto Id : Identifiers) {
|
||||||
|
TokensBeforeUnresolvedExpr.push_back(Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCompletionCallbacksImpl::completeNominalMemberBeginning(
|
void CodeCompletionCallbacksImpl::completeNominalMemberBeginning(
|
||||||
@@ -2900,12 +2968,18 @@ void CodeCompletionCallbacksImpl::doneParsing() {
|
|||||||
ExprParentFinder Walker(CurDeclContext->getASTContext().SourceMgr,
|
ExprParentFinder Walker(CurDeclContext->getASTContext().SourceMgr,
|
||||||
UnresolvedExpr, [&](Expr* E) { return true; });
|
UnresolvedExpr, [&](Expr* E) { return true; });
|
||||||
CurDeclContext->walkContext(Walker);
|
CurDeclContext->walkContext(Walker);
|
||||||
|
bool Success = false;
|
||||||
if(Walker.ParentExprFarthest) {
|
if(Walker.ParentExprFarthest) {
|
||||||
typeCheckUnresolvedMember(*CurDeclContext, UnresolvedExpr,
|
Success = typeCheckUnresolvedMember(*CurDeclContext, UnresolvedExpr,
|
||||||
Walker.ParentExprFarthest, PossibleTypes);
|
Walker.ParentExprFarthest,
|
||||||
|
PossibleTypes);
|
||||||
Lookup.getUnresolvedMemberCompletions(
|
Lookup.getUnresolvedMemberCompletions(
|
||||||
P.Context.SourceMgr.getCodeCompletionLoc(), PossibleTypes);
|
P.Context.SourceMgr.getCodeCompletionLoc(), PossibleTypes);
|
||||||
}
|
}
|
||||||
|
if (!Success) {
|
||||||
|
Lookup.getUnresolvedMemberCompletions(
|
||||||
|
P.Context.SourceMgr.getCodeCompletionLoc(), TokensBeforeUnresolvedExpr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,13 @@
|
|||||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_14 | FileCheck %s -check-prefix=UNRESOLVED_1
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_14 | FileCheck %s -check-prefix=UNRESOLVED_1
|
||||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_15 | FileCheck %s -check-prefix=UNRESOLVED_1
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_15 | FileCheck %s -check-prefix=UNRESOLVED_1
|
||||||
|
|
||||||
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_16 | FileCheck %s -check-prefix=UNRESOLVED_4
|
||||||
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_17 | FileCheck %s -check-prefix=UNRESOLVED_4
|
||||||
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_18 | FileCheck %s -check-prefix=UNRESOLVED_4
|
||||||
|
|
||||||
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_19 | FileCheck %s -check-prefix=UNRESOLVED_1
|
||||||
|
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_20 | FileCheck %s -check-prefix=UNRESOLVED_3
|
||||||
|
|
||||||
enum SomeEnum1 {
|
enum SomeEnum1 {
|
||||||
case South
|
case South
|
||||||
case North
|
case North
|
||||||
@@ -63,6 +70,11 @@ func OptionSetTaker6(Op1: SomeOptions2, Op2: SomeOptions1) {}
|
|||||||
|
|
||||||
func EnumTaker1(E : SomeEnum1) {}
|
func EnumTaker1(E : SomeEnum1) {}
|
||||||
|
|
||||||
|
class OptionTakerContainer1 {
|
||||||
|
func OptionSetTaker1(op : SomeOptions1) {}
|
||||||
|
func EnumTaker1(E : SomeEnum1) {}
|
||||||
|
}
|
||||||
|
|
||||||
class C1 {
|
class C1 {
|
||||||
func f1() {
|
func f1() {
|
||||||
var f : SomeOptions1
|
var f : SomeOptions1
|
||||||
@@ -147,7 +159,17 @@ OptionSetTaker5([.#^UNRESOLVED_15^#], .Option4, .South, .West)
|
|||||||
OptionSetTaker6(.#^UNRESOLVED_16^#, .Option4)
|
OptionSetTaker6(.#^UNRESOLVED_16^#, .Option4)
|
||||||
OptionSetTaker6(.Option4, .#^UNRESOLVED_17^#,)
|
OptionSetTaker6(.Option4, .#^UNRESOLVED_17^#,)
|
||||||
|
|
||||||
// FIXME: Unresolved member completion does not work inside closures.
|
|
||||||
var a = {() in
|
var a = {() in
|
||||||
OptionSetTaker5([.#^UNRESOLVED_18^#], .Option4, .South, .West)
|
OptionSetTaker5([.#^UNRESOLVED_18^#], .Option4, .South, .West)
|
||||||
}
|
}
|
||||||
|
var Containner = OptionTakerContainer1()
|
||||||
|
Container.OptionSetTaker1(.#^UNRESOLVED_19^#
|
||||||
|
Container.EnumTaker1(.#^UNRESOLVED_20^#
|
||||||
|
|
||||||
|
// UNRESOLVED_4: Begin completions
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option1[#SomeOptions1#]; name=Option1
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option2[#SomeOptions1#]; name=Option2
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option3[#SomeOptions1#]; name=Option3
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option4[#SomeOptions2#]; name=Option4
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option5[#SomeOptions2#]; name=Option5
|
||||||
|
// UNRESOLVED_4-DAG: Decl[StaticVar]/CurrNominal: Option6[#SomeOptions2#]; name=Option6
|
||||||
|
|||||||
Reference in New Issue
Block a user