mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
200 lines
6.5 KiB
C++
200 lines
6.5 KiB
C++
//===--- ConformingMethodList.cpp -----------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/IDE/ConformingMethodList.h"
|
|
#include "ExprContextAnalysis.h"
|
|
#include "swift/AST/ASTDemangler.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/USRGeneration.h"
|
|
#include "swift/Parse/CodeCompletionCallbacks.h"
|
|
#include "swift/Sema/IDETypeChecking.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/AST/Decl.h"
|
|
|
|
using namespace swift;
|
|
using namespace ide;
|
|
|
|
namespace {
|
|
class ConformingMethodListCallbacks : public CodeCompletionCallbacks {
|
|
ArrayRef<const char *> ExpectedTypeNames;
|
|
ConformingMethodListConsumer &Consumer;
|
|
SourceLoc Loc;
|
|
Expr *ParsedExpr = nullptr;
|
|
DeclContext *CurDeclContext = nullptr;
|
|
|
|
void getMatchingMethods(Type T,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl*> &expectedTypes,
|
|
SmallVectorImpl<ValueDecl *> &result);
|
|
|
|
public:
|
|
ConformingMethodListCallbacks(Parser &P,
|
|
ArrayRef<const char *> ExpectedTypeNames,
|
|
ConformingMethodListConsumer &Consumer)
|
|
: CodeCompletionCallbacks(P), ExpectedTypeNames(ExpectedTypeNames),
|
|
Consumer(Consumer) {}
|
|
|
|
// Only handle callbacks for suffix completions.
|
|
// {
|
|
void completeDotExpr(CodeCompletionExpr *E, SourceLoc DotLoc) override;
|
|
void completePostfixExpr(Expr *E, bool hasSpace) override;
|
|
// }
|
|
|
|
void doneParsing() override;
|
|
};
|
|
|
|
void ConformingMethodListCallbacks::completeDotExpr(CodeCompletionExpr *E,
|
|
SourceLoc DotLoc) {
|
|
CurDeclContext = P.CurDeclContext;
|
|
ParsedExpr = E->getBase();
|
|
}
|
|
|
|
void ConformingMethodListCallbacks::completePostfixExpr(Expr *E,
|
|
bool hasSpace) {
|
|
CurDeclContext = P.CurDeclContext;
|
|
ParsedExpr = E;
|
|
}
|
|
|
|
void ConformingMethodListCallbacks::doneParsing() {
|
|
if (!ParsedExpr)
|
|
return;
|
|
|
|
typeCheckContextAt(CurDeclContext, ParsedExpr->getLoc());
|
|
|
|
Type T = ParsedExpr->getType();
|
|
|
|
// Type check the expression if needed.
|
|
if (!T || T->is<ErrorType>()) {
|
|
ConcreteDeclRef ReferencedDecl = nullptr;
|
|
auto optT = getTypeOfCompletionContextExpr(P.Context, CurDeclContext,
|
|
CompletionTypeCheckKind::Normal,
|
|
ParsedExpr, ReferencedDecl);
|
|
if (!optT)
|
|
return;
|
|
T = *optT;
|
|
}
|
|
|
|
if (!T || T->is<ErrorType>() || T->is<UnresolvedType>())
|
|
return;
|
|
|
|
T = T->getRValueType();
|
|
if (T->hasArchetype())
|
|
T = T->mapTypeOutOfContext();
|
|
|
|
// If there are no (instance) members for this type, bail.
|
|
if (!T->mayHaveMembers() || T->is<ModuleType>()) {
|
|
return;
|
|
}
|
|
|
|
llvm::SmallPtrSet<ProtocolDecl*, 8> expectedProtocols;
|
|
for (auto Name: ExpectedTypeNames) {
|
|
if (auto *PD = resolveProtocolName(CurDeclContext, Name)) {
|
|
expectedProtocols.insert(PD);
|
|
}
|
|
}
|
|
|
|
// Collect the matching methods.
|
|
ConformingMethodListResult result(CurDeclContext, T);
|
|
getMatchingMethods(T, expectedProtocols, result.Members);
|
|
|
|
Consumer.handleResult(result);
|
|
}
|
|
|
|
void ConformingMethodListCallbacks::getMatchingMethods(
|
|
Type T, llvm::SmallPtrSetImpl<ProtocolDecl*> &expectedTypes,
|
|
SmallVectorImpl<ValueDecl *> &result) {
|
|
assert(T->mayHaveMembers() && !T->is<ModuleType>());
|
|
|
|
class LocalConsumer : public VisibleDeclConsumer {
|
|
ModuleDecl *CurModule;
|
|
|
|
/// The type of the parsed expression.
|
|
Type T;
|
|
|
|
/// The list of expected types.
|
|
llvm::SmallPtrSetImpl<ProtocolDecl*> &ExpectedTypes;
|
|
|
|
/// Result sink to populate.
|
|
SmallVectorImpl<ValueDecl *> &Result;
|
|
|
|
/// Returns true if \p VD is a instance method whose return type conforms
|
|
/// to the requested protocols.
|
|
bool isMatchingMethod(ValueDecl *VD) {
|
|
auto *FD = dyn_cast<FuncDecl>(VD);
|
|
if (!FD)
|
|
return false;
|
|
if (FD->isStatic() || FD->isOperator())
|
|
return false;
|
|
|
|
auto resultTy = T->getTypeOfMember(CurModule, FD,
|
|
FD->getResultInterfaceType());
|
|
if (resultTy->is<ErrorType>())
|
|
return false;
|
|
|
|
// The return type conforms to any of the requested protocols.
|
|
for (auto Proto : ExpectedTypes) {
|
|
if (CurModule->conformsToProtocol(resultTy, Proto))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
LocalConsumer(DeclContext *DC, Type T,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl*> &expectedTypes,
|
|
SmallVectorImpl<ValueDecl *> &result)
|
|
: CurModule(DC->getParentModule()), T(T), ExpectedTypes(expectedTypes),
|
|
Result(result) {}
|
|
|
|
void foundDecl(ValueDecl *VD, DeclVisibilityKind reason,
|
|
DynamicLookupInfo) override {
|
|
if (isMatchingMethod(VD) && !VD->shouldHideFromEditor())
|
|
Result.push_back(VD);
|
|
}
|
|
|
|
} LocalConsumer(CurDeclContext, T, expectedTypes, result);
|
|
|
|
lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext,
|
|
/*includeInstanceMembers=*/false,
|
|
/*includeDerivedRequirements*/false,
|
|
/*includeProtocolExtensionMembers*/true);
|
|
}
|
|
|
|
} // anonymous namespace.
|
|
|
|
CodeCompletionCallbacksFactory *
|
|
swift::ide::makeConformingMethodListCallbacksFactory(
|
|
ArrayRef<const char *> expectedTypeNames,
|
|
ConformingMethodListConsumer &Consumer) {
|
|
|
|
// CC callback factory which produces 'ContextInfoCallbacks'.
|
|
class ConformingMethodListCallbacksFactoryImpl
|
|
: public CodeCompletionCallbacksFactory {
|
|
ArrayRef<const char *> ExpectedTypeNames;
|
|
ConformingMethodListConsumer &Consumer;
|
|
|
|
public:
|
|
ConformingMethodListCallbacksFactoryImpl(
|
|
ArrayRef<const char *> ExpectedTypeNames,
|
|
ConformingMethodListConsumer &Consumer)
|
|
: ExpectedTypeNames(ExpectedTypeNames), Consumer(Consumer) {}
|
|
|
|
CodeCompletionCallbacks *createCodeCompletionCallbacks(Parser &P) override {
|
|
return new ConformingMethodListCallbacks(P, ExpectedTypeNames, Consumer);
|
|
}
|
|
};
|
|
|
|
return new ConformingMethodListCallbacksFactoryImpl(expectedTypeNames,
|
|
Consumer);
|
|
}
|