[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:
Xi Ge
2015-08-15 20:34:38 +00:00
parent 11376ca335
commit 5f8c122a79
2 changed files with 99 additions and 3 deletions

View File

@@ -696,6 +696,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
};
UnresolvedMemberExpr *UnresolvedExpr;
std::vector<std::string> TokensBeforeUnresolvedExpr;
CompletionKind Kind = CompletionKind::None;
Expr *ParsedExpr = nullptr;
SourceLoc DotLoc;
@@ -2114,6 +2115,63 @@ public:
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) {
NeedLeadingDot = !HaveDot;
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) {
llvm::SaveAndRestore<LookupKind> ChangeLookupKind(
Kind, LookupKind::EnumElement);
@@ -2565,6 +2630,9 @@ void CodeCompletionCallbacksImpl::completeUnresolvedMember(UnresolvedMemberExpr
Kind = CompletionKind::UnresolvedMember;
CurDeclContext = P.CurDeclContext;
UnresolvedExpr = E;
for (auto Id : Identifiers) {
TokensBeforeUnresolvedExpr.push_back(Id);
}
}
void CodeCompletionCallbacksImpl::completeNominalMemberBeginning(
@@ -2900,12 +2968,18 @@ void CodeCompletionCallbacksImpl::doneParsing() {
ExprParentFinder Walker(CurDeclContext->getASTContext().SourceMgr,
UnresolvedExpr, [&](Expr* E) { return true; });
CurDeclContext->walkContext(Walker);
bool Success = false;
if(Walker.ParentExprFarthest) {
typeCheckUnresolvedMember(*CurDeclContext, UnresolvedExpr,
Walker.ParentExprFarthest, PossibleTypes);
Success = typeCheckUnresolvedMember(*CurDeclContext, UnresolvedExpr,
Walker.ParentExprFarthest,
PossibleTypes);
Lookup.getUnresolvedMemberCompletions(
P.Context.SourceMgr.getCodeCompletionLoc(), PossibleTypes);
}
if (!Success) {
Lookup.getUnresolvedMemberCompletions(
P.Context.SourceMgr.getCodeCompletionLoc(), TokensBeforeUnresolvedExpr);
}
break;
}
}

View File

@@ -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_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 {
case South
case North
@@ -63,6 +70,11 @@ func OptionSetTaker6(Op1: SomeOptions2, Op2: SomeOptions1) {}
func EnumTaker1(E : SomeEnum1) {}
class OptionTakerContainer1 {
func OptionSetTaker1(op : SomeOptions1) {}
func EnumTaker1(E : SomeEnum1) {}
}
class C1 {
func f1() {
var f : SomeOptions1
@@ -147,7 +159,17 @@ OptionSetTaker5([.#^UNRESOLVED_15^#], .Option4, .South, .West)
OptionSetTaker6(.#^UNRESOLVED_16^#, .Option4)
OptionSetTaker6(.Option4, .#^UNRESOLVED_17^#,)
// FIXME: Unresolved member completion does not work inside closures.
var a = {() in
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