mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #22429 from rintaro/sourcekit-conformingmethods
[IDE/SourceKit] New SourceKit request for filtered method list
This commit is contained in:
66
include/swift/IDE/ConformingMethodList.h
Normal file
66
include/swift/IDE/ConformingMethodList.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//===--- ConformingMethodList.h --- -----------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef SWIFT_IDE_CONFORMINGMETHODLIST_H
|
||||||
|
#define SWIFT_IDE_CONFORMINGMETHODLIST_H
|
||||||
|
|
||||||
|
#include "swift/AST/Type.h"
|
||||||
|
#include "swift/Basic/LLVM.h"
|
||||||
|
|
||||||
|
namespace swift {
|
||||||
|
class CodeCompletionCallbacksFactory;
|
||||||
|
|
||||||
|
namespace ide {
|
||||||
|
|
||||||
|
/// A result item for context info query.
|
||||||
|
class ConformingMethodListResult {
|
||||||
|
public:
|
||||||
|
/// The decl context of the parsed expression.
|
||||||
|
DeclContext *DC;
|
||||||
|
|
||||||
|
/// The resolved type of the expression.
|
||||||
|
Type ExprType;
|
||||||
|
|
||||||
|
/// Methods which satisfy the criteria.
|
||||||
|
SmallVector<ValueDecl *, 0> Members;
|
||||||
|
|
||||||
|
ConformingMethodListResult(DeclContext *DC, Type ExprType)
|
||||||
|
: DC(DC), ExprType(ExprType) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An abstract base class for consumers of context info results.
|
||||||
|
class ConformingMethodListConsumer {
|
||||||
|
public:
|
||||||
|
virtual ~ConformingMethodListConsumer() {}
|
||||||
|
virtual void handleResult(const ConformingMethodListResult &result) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Printing consumer
|
||||||
|
class PrintingConformingMethodListConsumer
|
||||||
|
: public ConformingMethodListConsumer {
|
||||||
|
llvm::raw_ostream &OS;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PrintingConformingMethodListConsumer(llvm::raw_ostream &OS) : OS(OS) {}
|
||||||
|
|
||||||
|
void handleResult(const ConformingMethodListResult &result) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a factory for code completion callbacks.
|
||||||
|
CodeCompletionCallbacksFactory *makeConformingMethodListCallbacksFactory(
|
||||||
|
ArrayRef<const char *> expectedTypeNames,
|
||||||
|
ConformingMethodListConsumer &Consumer);
|
||||||
|
|
||||||
|
} // namespace ide
|
||||||
|
} // namespace swift
|
||||||
|
|
||||||
|
#endif // SWIFT_IDE_CONFORMINGMETHODLIST_H
|
||||||
@@ -117,35 +117,35 @@ public:
|
|||||||
|
|
||||||
/// Complete the whole expression. This is a fallback that should
|
/// Complete the whole expression. This is a fallback that should
|
||||||
/// produce results when more specific completion methods failed.
|
/// produce results when more specific completion methods failed.
|
||||||
virtual void completeExpr() = 0;
|
virtual void completeExpr() {};
|
||||||
|
|
||||||
/// Complete expr-dot after we have consumed the dot.
|
/// Complete expr-dot after we have consumed the dot.
|
||||||
virtual void completeDotExpr(Expr *E, SourceLoc DotLoc) = 0;
|
virtual void completeDotExpr(Expr *E, SourceLoc DotLoc) {};
|
||||||
|
|
||||||
/// Complete the beginning of a statement or expression.
|
/// Complete the beginning of a statement or expression.
|
||||||
virtual void completeStmtOrExpr() = 0;
|
virtual void completeStmtOrExpr() {};
|
||||||
|
|
||||||
/// Complete the beginning of expr-postfix -- no tokens provided
|
/// Complete the beginning of expr-postfix -- no tokens provided
|
||||||
/// by user.
|
/// by user.
|
||||||
virtual void completePostfixExprBeginning(CodeCompletionExpr *E) = 0;
|
virtual void completePostfixExprBeginning(CodeCompletionExpr *E) {};
|
||||||
|
|
||||||
/// Complete the beginning of expr-postfix in a for-each loop sequqence
|
/// Complete the beginning of expr-postfix in a for-each loop sequqence
|
||||||
/// -- no tokens provided by user.
|
/// -- no tokens provided by user.
|
||||||
virtual void completeForEachSequenceBeginning(CodeCompletionExpr *E) = 0;
|
virtual void completeForEachSequenceBeginning(CodeCompletionExpr *E) {};
|
||||||
|
|
||||||
/// Complete a given expr-postfix.
|
/// Complete a given expr-postfix.
|
||||||
virtual void completePostfixExpr(Expr *E, bool hasSpace) = 0;
|
virtual void completePostfixExpr(Expr *E, bool hasSpace) {};
|
||||||
|
|
||||||
/// Complete a given expr-postfix, given that there is a following
|
/// Complete a given expr-postfix, given that there is a following
|
||||||
/// left parenthesis.
|
/// left parenthesis.
|
||||||
virtual void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) = 0;
|
virtual void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) {};
|
||||||
|
|
||||||
/// Complete expr-super after we have consumed the 'super' keyword.
|
/// Complete expr-super after we have consumed the 'super' keyword.
|
||||||
virtual void completeExprSuper(SuperRefExpr *SRE) = 0;
|
virtual void completeExprSuper(SuperRefExpr *SRE) {};
|
||||||
|
|
||||||
/// Complete expr-super after we have consumed the 'super' keyword and
|
/// Complete expr-super after we have consumed the 'super' keyword and
|
||||||
/// a dot.
|
/// a dot.
|
||||||
virtual void completeExprSuperDot(SuperRefExpr *SRE) = 0;
|
virtual void completeExprSuperDot(SuperRefExpr *SRE) {};
|
||||||
|
|
||||||
/// Complete the argument to an Objective-C #keyPath
|
/// Complete the argument to an Objective-C #keyPath
|
||||||
/// expression.
|
/// expression.
|
||||||
@@ -153,59 +153,59 @@ public:
|
|||||||
/// \param KPE A partial #keyPath expression that can be used to
|
/// \param KPE A partial #keyPath expression that can be used to
|
||||||
/// provide context. This will be \c NULL if no components of the
|
/// provide context. This will be \c NULL if no components of the
|
||||||
/// #keyPath argument have been parsed yet.
|
/// #keyPath argument have been parsed yet.
|
||||||
virtual void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) = 0;
|
virtual void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) {};
|
||||||
|
|
||||||
/// Complete the beginning of type-simple -- no tokens provided
|
/// Complete the beginning of type-simple -- no tokens provided
|
||||||
/// by user.
|
/// by user.
|
||||||
virtual void completeTypeSimpleBeginning() = 0;
|
virtual void completeTypeSimpleBeginning() {};
|
||||||
|
|
||||||
/// Complete a given type-identifier after we have consumed the dot.
|
/// Complete a given type-identifier after we have consumed the dot.
|
||||||
virtual void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) = 0;
|
virtual void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) {};
|
||||||
|
|
||||||
/// Complete a given type-identifier when there is no trailing dot.
|
/// Complete a given type-identifier when there is no trailing dot.
|
||||||
virtual void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) = 0;
|
virtual void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) {};
|
||||||
|
|
||||||
/// Complete at the beginning of a case stmt pattern.
|
/// Complete at the beginning of a case stmt pattern.
|
||||||
virtual void completeCaseStmtBeginning() = 0;
|
virtual void completeCaseStmtBeginning() {};
|
||||||
|
|
||||||
/// Complete a case stmt pattern that starts with a dot.
|
/// Complete a case stmt pattern that starts with a dot.
|
||||||
virtual void completeCaseStmtDotPrefix() = 0;
|
virtual void completeCaseStmtDotPrefix() {};
|
||||||
|
|
||||||
/// Complete at the beginning of member of a nominal decl member -- no tokens
|
/// Complete at the beginning of member of a nominal decl member -- no tokens
|
||||||
/// provided by user.
|
/// provided by user.
|
||||||
virtual void completeNominalMemberBeginning(
|
virtual void completeNominalMemberBeginning(
|
||||||
SmallVectorImpl<StringRef> &Keywords) = 0;
|
SmallVectorImpl<StringRef> &Keywords) {};
|
||||||
|
|
||||||
/// Complete at the beginning of accessor in a accessor block.
|
/// Complete at the beginning of accessor in a accessor block.
|
||||||
virtual void completeAccessorBeginning() = 0;
|
virtual void completeAccessorBeginning() {};
|
||||||
|
|
||||||
/// Complete the keyword in attribute, for instance, @available.
|
/// Complete the keyword in attribute, for instance, @available.
|
||||||
virtual void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) = 0;
|
virtual void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) {};
|
||||||
|
|
||||||
/// Complete the parameters in attribute, for instance, version specifier for
|
/// Complete the parameters in attribute, for instance, version specifier for
|
||||||
/// @available.
|
/// @available.
|
||||||
virtual void completeDeclAttrParam(DeclAttrKind DK, int Index) = 0;
|
virtual void completeDeclAttrParam(DeclAttrKind DK, int Index) {};
|
||||||
|
|
||||||
/// Complete within a precedence group decl or after a colon in an
|
/// Complete within a precedence group decl or after a colon in an
|
||||||
/// operator decl.
|
/// operator decl.
|
||||||
virtual void completeInPrecedenceGroup(SyntaxKind SK) = 0;
|
virtual void completeInPrecedenceGroup(SyntaxKind SK) {};
|
||||||
|
|
||||||
/// Complete the platform names inside #available statements.
|
/// Complete the platform names inside #available statements.
|
||||||
virtual void completePoundAvailablePlatform() = 0;
|
virtual void completePoundAvailablePlatform() {};
|
||||||
|
|
||||||
/// Complete the import decl with importable modules.
|
/// Complete the import decl with importable modules.
|
||||||
virtual void
|
virtual void
|
||||||
completeImportDecl(std::vector<std::pair<Identifier, SourceLoc>> &Path) = 0;
|
completeImportDecl(std::vector<std::pair<Identifier, SourceLoc>> &Path) {};
|
||||||
|
|
||||||
/// Complete unresolved members after dot.
|
/// Complete unresolved members after dot.
|
||||||
virtual void completeUnresolvedMember(CodeCompletionExpr *E,
|
virtual void completeUnresolvedMember(CodeCompletionExpr *E,
|
||||||
SourceLoc DotLoc) = 0;
|
SourceLoc DotLoc) {};
|
||||||
|
|
||||||
virtual void completeAssignmentRHS(AssignExpr *E) = 0;
|
virtual void completeAssignmentRHS(AssignExpr *E) {};
|
||||||
|
|
||||||
virtual void completeCallArg(CodeCompletionExpr *E) = 0;
|
virtual void completeCallArg(CodeCompletionExpr *E) {};
|
||||||
|
|
||||||
virtual void completeReturnStmt(CodeCompletionExpr *E) = 0;
|
virtual void completeReturnStmt(CodeCompletionExpr *E) {};
|
||||||
|
|
||||||
/// Complete a yield statement. A missing yield index means that the
|
/// Complete a yield statement. A missing yield index means that the
|
||||||
/// completion immediately follows the 'yield' keyword; it may be either
|
/// completion immediately follows the 'yield' keyword; it may be either
|
||||||
@@ -213,18 +213,18 @@ public:
|
|||||||
/// index means that the completion is within the parentheses and is
|
/// index means that the completion is within the parentheses and is
|
||||||
/// for a specific yield value.
|
/// for a specific yield value.
|
||||||
virtual void completeYieldStmt(CodeCompletionExpr *E,
|
virtual void completeYieldStmt(CodeCompletionExpr *E,
|
||||||
Optional<unsigned> yieldIndex) = 0;
|
Optional<unsigned> yieldIndex) {};
|
||||||
|
|
||||||
virtual void completeAfterPoundExpr(CodeCompletionExpr *E,
|
virtual void completeAfterPoundExpr(CodeCompletionExpr *E,
|
||||||
Optional<StmtKind> ParentKind) = 0;
|
Optional<StmtKind> ParentKind) {};
|
||||||
|
|
||||||
virtual void completeAfterPoundDirective() = 0;
|
virtual void completeAfterPoundDirective() {};
|
||||||
|
|
||||||
virtual void completePlatformCondition() = 0;
|
virtual void completePlatformCondition() {};
|
||||||
|
|
||||||
virtual void completeAfterIfStmt(bool hasElse) = 0;
|
virtual void completeAfterIfStmt(bool hasElse) {};
|
||||||
|
|
||||||
virtual void completeGenericParams(TypeLoc TL) = 0;
|
virtual void completeGenericParams(TypeLoc TL) {};
|
||||||
|
|
||||||
/// Signals that the AST for the all the delayed-parsed code was
|
/// Signals that the AST for the all the delayed-parsed code was
|
||||||
/// constructed. No \c complete*() callbacks will be done after this.
|
/// constructed. No \c complete*() callbacks will be done after this.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ add_swift_host_library(swiftIDE STATIC
|
|||||||
CodeCompletion.cpp
|
CodeCompletion.cpp
|
||||||
CodeCompletionCache.cpp
|
CodeCompletionCache.cpp
|
||||||
CommentConversion.cpp
|
CommentConversion.cpp
|
||||||
|
ConformingMethodList.cpp
|
||||||
ExprContextAnalysis.cpp
|
ExprContextAnalysis.cpp
|
||||||
Formatting.cpp
|
Formatting.cpp
|
||||||
Refactoring.cpp
|
Refactoring.cpp
|
||||||
|
|||||||
@@ -374,48 +374,6 @@ static Stmt *findNearestStmt(const DeclContext *DC, SourceLoc Loc,
|
|||||||
const_cast<DeclContext *>(DC)->walkContext(Finder);
|
const_cast<DeclContext *>(DC)->walkContext(Finder);
|
||||||
return Finder.getFoundStmt();
|
return Finder.getFoundStmt();
|
||||||
}
|
}
|
||||||
/// Prepare the given expression for type-checking again, prinicipally by
|
|
||||||
/// erasing any ErrorType types on the given expression, allowing later
|
|
||||||
/// type-checking to make progress.
|
|
||||||
///
|
|
||||||
/// FIXME: this is fundamentally a workaround for the fact that we may end up
|
|
||||||
/// typechecking parts of an expression more than once - first for checking
|
|
||||||
/// the context, and later for checking more-specific things like unresolved
|
|
||||||
/// members. We should restructure code-completion type-checking so that we
|
|
||||||
/// never typecheck more than once (or find a more principled way to do it).
|
|
||||||
static void prepareForRetypechecking(Expr *E) {
|
|
||||||
assert(E);
|
|
||||||
struct Eraser : public ASTWalker {
|
|
||||||
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
||||||
if (expr && expr->getType() && (expr->getType()->hasError() ||
|
|
||||||
expr->getType()->hasUnresolvedType()))
|
|
||||||
expr->setType(Type());
|
|
||||||
if (auto *ACE = dyn_cast_or_null<AutoClosureExpr>(expr)) {
|
|
||||||
return { true, ACE->getSingleExpressionBody() };
|
|
||||||
}
|
|
||||||
return { true, expr };
|
|
||||||
}
|
|
||||||
bool walkToTypeLocPre(TypeLoc &TL) override {
|
|
||||||
if (TL.getType() && (TL.getType()->hasError() ||
|
|
||||||
TL.getType()->hasUnresolvedType()))
|
|
||||||
TL.setType(Type());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
|
|
||||||
if (P && P->hasType() && (P->getType()->hasError() ||
|
|
||||||
P->getType()->hasUnresolvedType())) {
|
|
||||||
P->setType(Type());
|
|
||||||
}
|
|
||||||
return { true, P };
|
|
||||||
}
|
|
||||||
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
|
||||||
return { false, S };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
E->walk(Eraser());
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeCompletionString::CodeCompletionString(ArrayRef<Chunk> Chunks) {
|
CodeCompletionString::CodeCompletionString(ArrayRef<Chunk> Chunks) {
|
||||||
std::uninitialized_copy(Chunks.begin(), Chunks.end(),
|
std::uninitialized_copy(Chunks.begin(), Chunks.end(),
|
||||||
|
|||||||
241
lib/IDE/ConformingMethodList.cpp
Normal file
241
lib/IDE/ConformingMethodList.cpp
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
//===--- 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 resolveExpectedTypes(ArrayRef<const char *> names, SourceLoc loc,
|
||||||
|
SmallVectorImpl<ProtocolDecl *> &result);
|
||||||
|
void getMatchingMethods(Type T, ArrayRef<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(Expr *E, SourceLoc DotLoc) override;
|
||||||
|
void completePostfixExpr(Expr *E, bool hasSpace) override;
|
||||||
|
// }
|
||||||
|
|
||||||
|
void doneParsing() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConformingMethodListCallbacks::completeDotExpr(Expr *E, SourceLoc DotLoc) {
|
||||||
|
CurDeclContext = P.CurDeclContext;
|
||||||
|
ParsedExpr = E;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConformingMethodListCallbacks::completePostfixExpr(Expr *E,
|
||||||
|
bool hasSpace) {
|
||||||
|
CurDeclContext = P.CurDeclContext;
|
||||||
|
ParsedExpr = E;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConformingMethodListCallbacks::doneParsing() {
|
||||||
|
if (!ParsedExpr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
typeCheckContextUntil(
|
||||||
|
CurDeclContext,
|
||||||
|
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
|
||||||
|
|
||||||
|
Type T = ParsedExpr->getType();
|
||||||
|
|
||||||
|
// Type check the expression if needed.
|
||||||
|
if (!T || T->is<ErrorType>()) {
|
||||||
|
prepareForRetypechecking(ParsedExpr);
|
||||||
|
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;
|
||||||
|
|
||||||
|
SmallVector<ProtocolDecl *, 4> expectedProtocols;
|
||||||
|
resolveExpectedTypes(ExpectedTypeNames, ParsedExpr->getLoc(),
|
||||||
|
expectedProtocols);
|
||||||
|
|
||||||
|
// Collect the matching methods.
|
||||||
|
ConformingMethodListResult result(CurDeclContext, T);
|
||||||
|
getMatchingMethods(T, expectedProtocols, result.Members);
|
||||||
|
|
||||||
|
Consumer.handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConformingMethodListCallbacks::resolveExpectedTypes(
|
||||||
|
ArrayRef<const char *> names, SourceLoc loc,
|
||||||
|
SmallVectorImpl<ProtocolDecl *> &result) {
|
||||||
|
auto &ctx = CurDeclContext->getASTContext();
|
||||||
|
|
||||||
|
for (auto name : names) {
|
||||||
|
if (auto ty = Demangle::getTypeForMangling(ctx, name)) {
|
||||||
|
if (auto Proto = dyn_cast_or_null<ProtocolDecl>(ty->getAnyGeneric()))
|
||||||
|
result.push_back(Proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConformingMethodListCallbacks::getMatchingMethods(
|
||||||
|
Type T, ArrayRef<ProtocolDecl *> expectedTypes,
|
||||||
|
SmallVectorImpl<ValueDecl *> &result) {
|
||||||
|
if (!T->mayHaveMembers())
|
||||||
|
return;
|
||||||
|
|
||||||
|
class LocalConsumer : public VisibleDeclConsumer {
|
||||||
|
ModuleDecl *CurModule;
|
||||||
|
|
||||||
|
/// The type of the parsed expression.
|
||||||
|
Type T;
|
||||||
|
|
||||||
|
/// The list of expected types.
|
||||||
|
ArrayRef<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) {
|
||||||
|
if (!isa<FuncDecl>(VD))
|
||||||
|
return false;
|
||||||
|
if (VD->isStatic() || VD->isOperator())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto declTy = T->getTypeOfMember(CurModule, VD);
|
||||||
|
if (declTy->is<ErrorType>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Strip '(Self.Type) ->' and parameters.
|
||||||
|
declTy = declTy->castTo<AnyFunctionType>()->getResult();
|
||||||
|
declTy = declTy->castTo<AnyFunctionType>()->getResult();
|
||||||
|
|
||||||
|
// The return type conforms to any of the requested protocols.
|
||||||
|
for (auto Proto : ExpectedTypes) {
|
||||||
|
if (CurModule->conformsToProtocol(declTy, Proto))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
LocalConsumer(DeclContext *DC, Type T,
|
||||||
|
ArrayRef<ProtocolDecl *> expectedTypes,
|
||||||
|
SmallVectorImpl<ValueDecl *> &result)
|
||||||
|
: CurModule(DC->getParentModule()), T(T), ExpectedTypes(expectedTypes),
|
||||||
|
Result(result) {}
|
||||||
|
|
||||||
|
void foundDecl(ValueDecl *VD, DeclVisibilityKind reason) {
|
||||||
|
if (isMatchingMethod(VD) && !VD->shouldHideFromEditor())
|
||||||
|
Result.push_back(VD);
|
||||||
|
}
|
||||||
|
|
||||||
|
} LocalConsumer(CurDeclContext, T, expectedTypes, result);
|
||||||
|
|
||||||
|
lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext,
|
||||||
|
CurDeclContext->getASTContext().getLazyResolver(),
|
||||||
|
/*includeInstanceMembers=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace.
|
||||||
|
|
||||||
|
void PrintingConformingMethodListConsumer::handleResult(
|
||||||
|
const ConformingMethodListResult &result) {
|
||||||
|
OS << "-----BEGIN CONFORMING METHOD LIST-----\n";
|
||||||
|
|
||||||
|
OS << "- TypeName: ";
|
||||||
|
result.ExprType.print(OS);
|
||||||
|
OS << "\n";
|
||||||
|
|
||||||
|
OS << "- Members: ";
|
||||||
|
if (result.Members.empty())
|
||||||
|
OS << " []";
|
||||||
|
OS << "\n";
|
||||||
|
for (auto VD : result.Members) {
|
||||||
|
auto funcTy = cast<FuncDecl>(VD)->getMethodInterfaceType();
|
||||||
|
funcTy = result.ExprType->getTypeOfMember(result.DC->getParentModule(), VD,
|
||||||
|
funcTy);
|
||||||
|
auto resultTy = funcTy->castTo<FunctionType>()->getResult();
|
||||||
|
|
||||||
|
OS << " - Name: ";
|
||||||
|
VD->getFullName().print(OS);
|
||||||
|
OS << "\n";
|
||||||
|
|
||||||
|
OS << " TypeName: ";
|
||||||
|
resultTy.print(OS);
|
||||||
|
OS << "\n";
|
||||||
|
|
||||||
|
StringRef BriefDoc = VD->getBriefComment();
|
||||||
|
if (!BriefDoc.empty()) {
|
||||||
|
OS << " DocBrief: \"";
|
||||||
|
OS << VD->getBriefComment();
|
||||||
|
OS << "\"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OS << "-----END CONFORMING METHOD LIST-----\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -30,6 +30,53 @@
|
|||||||
using namespace swift;
|
using namespace swift;
|
||||||
using namespace ide;
|
using namespace ide;
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// prepareForRetypechecking(Expr *)
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// Prepare the given expression for type-checking again, prinicipally by
|
||||||
|
/// erasing any ErrorType types on the given expression, allowing later
|
||||||
|
/// type-checking to make progress.
|
||||||
|
///
|
||||||
|
/// FIXME: this is fundamentally a workaround for the fact that we may end up
|
||||||
|
/// typechecking parts of an expression more than once - first for checking
|
||||||
|
/// the context, and later for checking more-specific things like unresolved
|
||||||
|
/// members. We should restructure code-completion type-checking so that we
|
||||||
|
/// never typecheck more than once (or find a more principled way to do it).
|
||||||
|
void swift::ide::prepareForRetypechecking(Expr *E) {
|
||||||
|
assert(E);
|
||||||
|
struct Eraser : public ASTWalker {
|
||||||
|
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
|
||||||
|
if (expr && expr->getType() && (expr->getType()->hasError() ||
|
||||||
|
expr->getType()->hasUnresolvedType()))
|
||||||
|
expr->setType(Type());
|
||||||
|
if (auto *ACE = dyn_cast_or_null<AutoClosureExpr>(expr)) {
|
||||||
|
return { true, ACE->getSingleExpressionBody() };
|
||||||
|
}
|
||||||
|
return { true, expr };
|
||||||
|
}
|
||||||
|
bool walkToTypeLocPre(TypeLoc &TL) override {
|
||||||
|
if (TL.getType() && (TL.getType()->hasError() ||
|
||||||
|
TL.getType()->hasUnresolvedType()))
|
||||||
|
TL.setType(Type());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
|
||||||
|
if (P && P->hasType() && (P->getType()->hasError() ||
|
||||||
|
P->getType()->hasUnresolvedType())) {
|
||||||
|
P->setType(Type());
|
||||||
|
}
|
||||||
|
return { true, P };
|
||||||
|
}
|
||||||
|
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
||||||
|
return { false, S };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
E->walk(Eraser());
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// typeCheckContextUntil(DeclContext, SourceLoc)
|
// typeCheckContextUntil(DeclContext, SourceLoc)
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ class AnyFunctionType;
|
|||||||
|
|
||||||
namespace ide {
|
namespace ide {
|
||||||
|
|
||||||
|
/// Prepare the given expression for type-checking again, prinicipally by
|
||||||
|
/// erasing any ErrorType types on the given expression, allowing later
|
||||||
|
/// type-checking to make progress.
|
||||||
|
void prepareForRetypechecking(Expr *E);
|
||||||
|
|
||||||
/// Type check parent contexts of the given decl context, and the body of the
|
/// Type check parent contexts of the given decl context, and the body of the
|
||||||
/// given context until \c Loc if the context is a function body.
|
/// given context until \c Loc if the context is a function body.
|
||||||
void typeCheckContextUntil(DeclContext *DC, SourceLoc Loc);
|
void typeCheckContextUntil(DeclContext *DC, SourceLoc Loc);
|
||||||
|
|||||||
@@ -35,45 +35,10 @@ public:
|
|||||||
ContextInfoCallbacks(Parser &P, TypeContextInfoConsumer &Consumer)
|
ContextInfoCallbacks(Parser &P, TypeContextInfoConsumer &Consumer)
|
||||||
: CodeCompletionCallbacks(P), Consumer(Consumer) {}
|
: CodeCompletionCallbacks(P), Consumer(Consumer) {}
|
||||||
|
|
||||||
void completeExpr() override{};
|
|
||||||
|
|
||||||
// Ignore callbacks for suffix completions
|
|
||||||
// {
|
|
||||||
void completeDotExpr(Expr *E, SourceLoc DotLoc) override {};
|
|
||||||
void completePostfixExpr(Expr *E, bool hasSpace) override {};
|
|
||||||
void completeExprSuper(SuperRefExpr *SRE) override {};
|
|
||||||
void completeExprSuperDot(SuperRefExpr *SRE) override {};
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ignore non-expression callbacks.
|
|
||||||
// {
|
|
||||||
void completeInPrecedenceGroup(SyntaxKind SK) override {};
|
|
||||||
void completePoundAvailablePlatform() override {};
|
|
||||||
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override {}
|
|
||||||
void completeTypeSimpleBeginning() override {}
|
|
||||||
void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override {}
|
|
||||||
void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override {}
|
|
||||||
void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) override {}
|
|
||||||
void completeDeclAttrParam(DeclAttrKind DK, int Index) override {}
|
|
||||||
void completeNominalMemberBeginning(
|
|
||||||
SmallVectorImpl<StringRef> &Keywords) override {}
|
|
||||||
void completeImportDecl(
|
|
||||||
std::vector<std::pair<Identifier, SourceLoc>> &Path) override {}
|
|
||||||
void completeAfterPoundExpr(CodeCompletionExpr *E,
|
|
||||||
Optional<StmtKind> ParentKind) override {}
|
|
||||||
void completeAfterPoundDirective() override {}
|
|
||||||
void completePlatformCondition() override {}
|
|
||||||
void completeGenericParams(TypeLoc TL) override {}
|
|
||||||
void completeAfterIfStmt(bool hasElse) override {}
|
|
||||||
void completeAccessorBeginning() override {};
|
|
||||||
// }
|
|
||||||
|
|
||||||
void completeStmtOrExpr() override {};
|
|
||||||
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
|
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
|
||||||
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
|
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
|
||||||
void completeCaseStmtBeginning() override;
|
void completeCaseStmtBeginning() override;
|
||||||
|
|
||||||
void completeAssignmentRHS(AssignExpr *E) override {};
|
|
||||||
void completeCallArg(CodeCompletionExpr *E) override;
|
void completeCallArg(CodeCompletionExpr *E) override;
|
||||||
void completeReturnStmt(CodeCompletionExpr *E) override;
|
void completeReturnStmt(CodeCompletionExpr *E) override;
|
||||||
void completeYieldStmt(CodeCompletionExpr *E,
|
void completeYieldStmt(CodeCompletionExpr *E,
|
||||||
@@ -83,8 +48,6 @@ public:
|
|||||||
SourceLoc DotLoc) override;
|
SourceLoc DotLoc) override;
|
||||||
void completeCaseStmtDotPrefix() override;
|
void completeCaseStmtDotPrefix() override;
|
||||||
|
|
||||||
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override{};
|
|
||||||
|
|
||||||
void doneParsing() override;
|
void doneParsing() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
49
test/IDE/conforming-methods-basic.swift
Normal file
49
test/IDE/conforming-methods-basic.swift
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=TEST_1 -module-name MyModule -conforming-methods-expected-types '$s8MyModule7Target1PD' -conforming-methods-expected-types '$s8MyModule7Target2PD' | %FileCheck %s -check-prefix=CHECK_1
|
||||||
|
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=TEST_2 -module-name MyModule -conforming-methods-expected-types '$s8MyModule7Target1PD' -conforming-methods-expected-types '$s8MyModule7Target2PD' | %FileCheck %s -check-prefix=CHECK_1
|
||||||
|
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=TEST_3 -module-name MyModule -conforming-methods-expected-types '$s8MyModule7Target1PD' -conforming-methods-expected-types '$s8MyModule7Target2PD' | %FileCheck %s -check-prefix=CHECK_1
|
||||||
|
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=TEST_4 -module-name MyModule -conforming-methods-expected-types '$s8MyModule7Target1PD' -conforming-methods-expected-types '$s8MyModule7Target2PD' | %FileCheck %s -check-prefix=CHECK_1
|
||||||
|
|
||||||
|
protocol Target1 {
|
||||||
|
associatedType Assoc
|
||||||
|
}
|
||||||
|
protocol Target2 {}
|
||||||
|
protocol Target3 {}
|
||||||
|
|
||||||
|
struct ConcreteTarget1 : Target1 {}
|
||||||
|
struct ConcreteTarget2 : Target2 {}
|
||||||
|
struct ConcreteTarget3 : Target3 {}
|
||||||
|
|
||||||
|
|
||||||
|
struct C {
|
||||||
|
func returnsConcreteTarget1() -> ConcreteTarget1 { fatalError() }
|
||||||
|
func returnsExistentialTarget1() -> Target1 { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol P {
|
||||||
|
func returnsConcreteTarget2() -> ConcreteTarget2
|
||||||
|
func returnsConcreteTarget3() -> ConcreteTarget3
|
||||||
|
}
|
||||||
|
|
||||||
|
extension P {
|
||||||
|
func returnSelf() -> Self { return self }
|
||||||
|
func returnsConcreteTarget2() -> ConcreteTarget2 { fatalError() }
|
||||||
|
func returnsConcreteTarget3() -> ConcreteTarget3 { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension C : P {}
|
||||||
|
|
||||||
|
func testing(obj: C) {
|
||||||
|
let _ = obj #^TEST_1^#
|
||||||
|
let _ = obj .#^TEST_2^#
|
||||||
|
let _ = obj.returnSelf()#^TEST_3^#
|
||||||
|
let _ = obj.returnSelf().#^TEST_4^#
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK_1: -----BEGIN CONFORMING METHOD LIST-----
|
||||||
|
// CHECK_1_NEXT: - TypeName: C
|
||||||
|
// CHECK_1_NEXT: - Members:
|
||||||
|
// CHECK_1_NEXT: - Name: returnsConcreteTarget1()
|
||||||
|
// CHECK_1_NEXT: TypeName: ConcreteTarget1
|
||||||
|
// CHECK_1_NEXT: - Name: returnsConcreteTarget1()
|
||||||
|
// CHECK_1_NEXT: TypeName: ConcreteTarget1
|
||||||
|
// CHECK_1_NEXT: -----END CONFORMING METHOD LIST-----
|
||||||
30
test/SourceKit/ConformingMethods/basic.swift
Normal file
30
test/SourceKit/ConformingMethods/basic.swift
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
protocol Target1 {}
|
||||||
|
protocol Target2 {}
|
||||||
|
protocol Target3 {}
|
||||||
|
|
||||||
|
struct ConcreteTarget1 : Target1 {}
|
||||||
|
struct ConcreteTarget2 : Target2 {}
|
||||||
|
struct ConcreteTarget3 : Target3 {}
|
||||||
|
|
||||||
|
protocol P {
|
||||||
|
associatedtype Assoc
|
||||||
|
func protocolMethod(asc: Assoc) -> Self
|
||||||
|
}
|
||||||
|
extension P {
|
||||||
|
func protocolMethod(asc: Assoc) -> Self { return self }
|
||||||
|
}
|
||||||
|
|
||||||
|
class C : P {
|
||||||
|
typealias Assoc = String
|
||||||
|
static func staticMethod() -> Self {}
|
||||||
|
func instanceMethod(x: Int) -> C {}
|
||||||
|
func methodForTarget1() -> ConcreteTarget1 {}
|
||||||
|
func methodForTarget2() -> ConcreteTarget2 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testing(obj: C) {
|
||||||
|
let _ = obj.
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUN: %sourcekitd-test -req=conformingmethods -pos=26:14 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s > %t.response
|
||||||
|
// RUN: diff -u %s.response %t.response
|
||||||
20
test/SourceKit/ConformingMethods/basic.swift.response
Normal file
20
test/SourceKit/ConformingMethods/basic.swift.response
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
key.typename: "C",
|
||||||
|
key.typeusr: "$s8MyModule1CCD",
|
||||||
|
key.members: [
|
||||||
|
{
|
||||||
|
key.name: "methodForTarget1()",
|
||||||
|
key.sourcetext: "methodForTarget1()",
|
||||||
|
key.description: "methodForTarget1()",
|
||||||
|
key.typename: "ConcreteTarget1",
|
||||||
|
key.typeusr: "$s8MyModule15ConcreteTarget1VD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key.name: "methodForTarget2()",
|
||||||
|
key.sourcetext: "methodForTarget2()",
|
||||||
|
key.description: "methodForTarget2()",
|
||||||
|
key.typename: "ConcreteTarget2",
|
||||||
|
key.typeusr: "$s8MyModule15ConcreteTarget2VD"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -533,6 +533,31 @@ public:
|
|||||||
virtual void failed(StringRef ErrDescription) = 0;
|
virtual void failed(StringRef ErrDescription) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConformingMethodListResult {
|
||||||
|
StringRef TypeName;
|
||||||
|
StringRef TypeUSR;
|
||||||
|
|
||||||
|
struct Member {
|
||||||
|
StringRef Name;
|
||||||
|
StringRef TypeName;
|
||||||
|
StringRef TypeUSR;
|
||||||
|
StringRef Description;
|
||||||
|
StringRef SourceText;
|
||||||
|
StringRef DocBrief;
|
||||||
|
};
|
||||||
|
ArrayRef<Member> Members;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConformingMethodListConsumer {
|
||||||
|
virtual void anchor();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~ConformingMethodListConsumer() {}
|
||||||
|
|
||||||
|
virtual void handleResult(const ConformingMethodListResult &Result) = 0;
|
||||||
|
virtual void failed(StringRef ErrDescription) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class LangSupport {
|
class LangSupport {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
|
|
||||||
@@ -693,6 +718,12 @@ public:
|
|||||||
ArrayRef<const char *> Args,
|
ArrayRef<const char *> Args,
|
||||||
TypeContextInfoConsumer &Consumer) = 0;
|
TypeContextInfoConsumer &Consumer) = 0;
|
||||||
|
|
||||||
|
virtual void getConformingMethodList(llvm::MemoryBuffer *inputBuf,
|
||||||
|
unsigned Offset,
|
||||||
|
ArrayRef<const char *> Args,
|
||||||
|
ArrayRef<const char *> ExpectedTypes,
|
||||||
|
ConformingMethodListConsumer &Consumer) = 0;
|
||||||
|
|
||||||
virtual void getStatistics(StatisticsReceiver) = 0;
|
virtual void getStatistics(StatisticsReceiver) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,4 +20,5 @@ void EditorConsumer::anchor() { }
|
|||||||
void OptionsDictionary::anchor() {}
|
void OptionsDictionary::anchor() {}
|
||||||
void DocInfoConsumer::anchor() { }
|
void DocInfoConsumer::anchor() { }
|
||||||
void TypeContextInfoConsumer::anchor() { }
|
void TypeContextInfoConsumer::anchor() { }
|
||||||
|
void ConformingMethodListConsumer::anchor() { }
|
||||||
void LangSupport::anchor() { }
|
void LangSupport::anchor() { }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ add_sourcekit_library(SourceKitSwiftLang
|
|||||||
CodeCompletionOrganizer.cpp
|
CodeCompletionOrganizer.cpp
|
||||||
SwiftASTManager.cpp
|
SwiftASTManager.cpp
|
||||||
SwiftCompletion.cpp
|
SwiftCompletion.cpp
|
||||||
|
SwiftConformingMethodList.cpp
|
||||||
SwiftDocSupport.cpp
|
SwiftDocSupport.cpp
|
||||||
SwiftEditor.cpp
|
SwiftEditor.cpp
|
||||||
SwiftEditorInterfaceGen.cpp
|
SwiftEditorInterfaceGen.cpp
|
||||||
|
|||||||
213
tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp
Normal file
213
tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
//===--- SwiftConformingMethodList.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 "SwiftASTManager.h"
|
||||||
|
#include "SwiftEditorDiagConsumer.h"
|
||||||
|
#include "SwiftLangSupport.h"
|
||||||
|
#include "swift/Frontend/Frontend.h"
|
||||||
|
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
||||||
|
#include "swift/IDE/ConformingMethodList.h"
|
||||||
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/Comment.h"
|
||||||
|
#include "clang/AST/Decl.h"
|
||||||
|
#include "clang/AST/Type.h"
|
||||||
|
|
||||||
|
using namespace SourceKit;
|
||||||
|
using namespace swift;
|
||||||
|
using namespace ide;
|
||||||
|
|
||||||
|
static bool swiftConformingMethodListImpl(
|
||||||
|
SwiftLangSupport &Lang, llvm::MemoryBuffer *UnresolvedInputFile,
|
||||||
|
unsigned Offset, ArrayRef<const char *> Args,
|
||||||
|
ArrayRef<const char *> ExpectedTypeNames,
|
||||||
|
ide::ConformingMethodListConsumer &Consumer, std::string &Error) {
|
||||||
|
auto bufferIdentifier =
|
||||||
|
Lang.resolvePathSymlinks(UnresolvedInputFile->getBufferIdentifier());
|
||||||
|
|
||||||
|
auto origOffset = Offset;
|
||||||
|
auto newBuffer = SwiftLangSupport::makeCodeCompletionMemoryBuffer(
|
||||||
|
UnresolvedInputFile, Offset, bufferIdentifier);
|
||||||
|
|
||||||
|
CompilerInstance CI;
|
||||||
|
PrintingDiagnosticConsumer PrintDiags;
|
||||||
|
CI.addDiagnosticConsumer(&PrintDiags);
|
||||||
|
|
||||||
|
EditorDiagConsumer TraceDiags;
|
||||||
|
trace::TracedOperation TracedOp(trace::OperationKind::CodeCompletion);
|
||||||
|
if (TracedOp.enabled()) {
|
||||||
|
CI.addDiagnosticConsumer(&TraceDiags);
|
||||||
|
trace::SwiftInvocation SwiftArgs;
|
||||||
|
trace::initTraceInfo(SwiftArgs, bufferIdentifier, Args);
|
||||||
|
TracedOp.setDiagnosticProvider(
|
||||||
|
[&TraceDiags](SmallVectorImpl<DiagnosticEntryInfo> &diags) {
|
||||||
|
TraceDiags.getAllDiagnostics(diags);
|
||||||
|
});
|
||||||
|
TracedOp.start(
|
||||||
|
SwiftArgs,
|
||||||
|
{std::make_pair("OriginalOffset", std::to_string(origOffset)),
|
||||||
|
std::make_pair("Offset", std::to_string(Offset))});
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerInvocation Invocation;
|
||||||
|
bool Failed = Lang.getASTManager()->initCompilerInvocation(
|
||||||
|
Invocation, Args, CI.getDiags(), bufferIdentifier, Error);
|
||||||
|
if (Failed)
|
||||||
|
return false;
|
||||||
|
if (!Invocation.getFrontendOptions().InputsAndOutputs.hasInputs()) {
|
||||||
|
Error = "no input filenames specified";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Invocation.setCodeCompletionPoint(newBuffer.get(), Offset);
|
||||||
|
|
||||||
|
// Create a factory for code completion callbacks that will feed the
|
||||||
|
// Consumer.
|
||||||
|
std::unique_ptr<CodeCompletionCallbacksFactory> callbacksFactory(
|
||||||
|
ide::makeConformingMethodListCallbacksFactory(ExpectedTypeNames,
|
||||||
|
Consumer));
|
||||||
|
|
||||||
|
Invocation.setCodeCompletionFactory(callbacksFactory.get());
|
||||||
|
|
||||||
|
if (CI.setup(Invocation)) {
|
||||||
|
// FIXME: error?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CI.performSema();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwiftLangSupport::getConformingMethodList(
|
||||||
|
llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset,
|
||||||
|
ArrayRef<const char *> Args, ArrayRef<const char *> ExpectedTypeNames,
|
||||||
|
SourceKit::ConformingMethodListConsumer &SKConsumer) {
|
||||||
|
|
||||||
|
class Consumer : public ide::ConformingMethodListConsumer {
|
||||||
|
SourceKit::ConformingMethodListConsumer &SKConsumer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Consumer(SourceKit::ConformingMethodListConsumer &SKConsumer)
|
||||||
|
: SKConsumer(SKConsumer) {}
|
||||||
|
|
||||||
|
/// Convert an IDE result to a SK result and send it to \c SKConsumer .
|
||||||
|
void handleResult(const ide::ConformingMethodListResult &Result) {
|
||||||
|
SmallString<512> SS;
|
||||||
|
llvm::raw_svector_ostream OS(SS);
|
||||||
|
|
||||||
|
unsigned TypeNameBegin = SS.size();
|
||||||
|
Result.ExprType.print(OS);
|
||||||
|
unsigned TypeNameLength = SS.size() - TypeNameBegin;
|
||||||
|
|
||||||
|
unsigned TypeUSRBegin = SS.size();
|
||||||
|
SwiftLangSupport::printTypeUSR(Result.ExprType, OS);
|
||||||
|
unsigned TypeUSRLength = SS.size() - TypeUSRBegin;
|
||||||
|
|
||||||
|
struct MemberInfo {
|
||||||
|
size_t DeclNameBegin = 0;
|
||||||
|
size_t DeclNameLength = 0;
|
||||||
|
size_t TypeNameBegin = 0;
|
||||||
|
size_t TypeNameLength = 0;
|
||||||
|
size_t TypeUSRBegin = 0;
|
||||||
|
size_t TypeUSRLength = 0;
|
||||||
|
size_t DescriptionBegin = 0;
|
||||||
|
size_t DescriptionLength = 0;
|
||||||
|
size_t SourceTextBegin = 0;
|
||||||
|
size_t SourceTextLength = 0;
|
||||||
|
StringRef BriefComment;
|
||||||
|
|
||||||
|
MemberInfo() {}
|
||||||
|
};
|
||||||
|
SmallVector<MemberInfo, 8> Members;
|
||||||
|
|
||||||
|
for (auto member : Result.Members) {
|
||||||
|
Members.emplace_back();
|
||||||
|
auto &memberElem = Members.back();
|
||||||
|
|
||||||
|
auto funcTy = cast<FuncDecl>(member)->getMethodInterfaceType();
|
||||||
|
funcTy = Result.ExprType->getTypeOfMember(Result.DC->getParentModule(),
|
||||||
|
member, funcTy);
|
||||||
|
auto resultTy = funcTy->castTo<FunctionType>()->getResult();
|
||||||
|
|
||||||
|
// Name.
|
||||||
|
memberElem.DeclNameBegin = SS.size();
|
||||||
|
member->getFullName().print(OS);
|
||||||
|
memberElem.DeclNameLength = SS.size() - memberElem.DeclNameBegin;
|
||||||
|
|
||||||
|
// Type name.
|
||||||
|
memberElem.TypeNameBegin = SS.size();
|
||||||
|
resultTy.print(OS);
|
||||||
|
memberElem.TypeNameLength = SS.size() - memberElem.TypeNameBegin;
|
||||||
|
|
||||||
|
// Type USR.
|
||||||
|
memberElem.TypeUSRBegin = SS.size();
|
||||||
|
SwiftLangSupport::printTypeUSR(resultTy, OS);
|
||||||
|
memberElem.TypeUSRLength = SS.size() - memberElem.TypeUSRBegin;
|
||||||
|
|
||||||
|
// Description.
|
||||||
|
memberElem.DescriptionBegin = SS.size();
|
||||||
|
SwiftLangSupport::printMemberDeclDescription(
|
||||||
|
member, Result.ExprType, /*usePlaceholder=*/false, OS);
|
||||||
|
memberElem.DescriptionLength =
|
||||||
|
SS.size() - memberElem.DescriptionBegin;
|
||||||
|
|
||||||
|
// Sourcetext.
|
||||||
|
memberElem.SourceTextBegin = SS.size();
|
||||||
|
SwiftLangSupport::printMemberDeclDescription(
|
||||||
|
member, Result.ExprType, /*usePlaceholder=*/true, OS);
|
||||||
|
memberElem.SourceTextLength =
|
||||||
|
SS.size() - memberElem.SourceTextBegin;
|
||||||
|
|
||||||
|
// DocBrief.
|
||||||
|
auto MaybeClangNode = member->getClangNode();
|
||||||
|
if (MaybeClangNode) {
|
||||||
|
if (auto *D = MaybeClangNode.getAsDecl()) {
|
||||||
|
const auto &ClangContext = D->getASTContext();
|
||||||
|
if (const clang::RawComment *RC =
|
||||||
|
ClangContext.getRawCommentForAnyRedecl(D))
|
||||||
|
memberElem.BriefComment = RC->getBriefText(ClangContext);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memberElem.BriefComment = member->getBriefComment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceKit::ConformingMethodListResult SKResult;
|
||||||
|
SmallVector<SourceKit::ConformingMethodListResult::Member, 8>
|
||||||
|
SKMembers;
|
||||||
|
|
||||||
|
for (auto info : Members) {
|
||||||
|
StringRef Name(SS.begin() + info.DeclNameBegin, info.DeclNameLength);
|
||||||
|
StringRef TypeName(SS.begin() + info.TypeNameBegin,
|
||||||
|
info.TypeNameLength);
|
||||||
|
StringRef TypeUSR(SS.begin() + info.TypeUSRBegin, info.TypeUSRLength);
|
||||||
|
StringRef Description(SS.begin() + info.DescriptionBegin,
|
||||||
|
info.DescriptionLength);
|
||||||
|
StringRef SourceText(SS.begin() + info.SourceTextBegin,
|
||||||
|
info.SourceTextLength);
|
||||||
|
SKMembers.push_back({Name, TypeName, TypeUSR, Description, SourceText,
|
||||||
|
info.BriefComment});
|
||||||
|
}
|
||||||
|
|
||||||
|
SKResult.TypeName = StringRef(SS.begin() + TypeNameBegin, TypeNameLength);
|
||||||
|
SKResult.TypeUSR = StringRef(SS.begin() + TypeUSRBegin, TypeUSRLength);
|
||||||
|
SKResult.Members = SKMembers;
|
||||||
|
|
||||||
|
SKConsumer.handleResult(SKResult);
|
||||||
|
}
|
||||||
|
} Consumer(SKConsumer);
|
||||||
|
|
||||||
|
std::string Error;
|
||||||
|
if (!swiftConformingMethodListImpl(*this, UnresolvedInputFile, Offset, Args,
|
||||||
|
ExpectedTypeNames, Consumer, Error)) {
|
||||||
|
SKConsumer.failed(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "swift/AST/ASTVisitor.h"
|
#include "swift/AST/ASTVisitor.h"
|
||||||
#include "swift/AST/ClangModuleLoader.h"
|
#include "swift/AST/ClangModuleLoader.h"
|
||||||
|
#include "swift/AST/ParameterList.h"
|
||||||
#include "swift/AST/SILOptions.h"
|
#include "swift/AST/SILOptions.h"
|
||||||
#include "swift/AST/USRGeneration.h"
|
#include "swift/AST/USRGeneration.h"
|
||||||
#include "swift/Config.h"
|
#include "swift/Config.h"
|
||||||
@@ -190,6 +191,26 @@ SwiftLangSupport::SwiftLangSupport(SourceKit::Context &SKCtx)
|
|||||||
SwiftLangSupport::~SwiftLangSupport() {
|
SwiftLangSupport::~SwiftLangSupport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<llvm::MemoryBuffer>
|
||||||
|
SwiftLangSupport::makeCodeCompletionMemoryBuffer(
|
||||||
|
const llvm::MemoryBuffer *origBuf, unsigned &Offset,
|
||||||
|
const std::string bufferIdentifier) {
|
||||||
|
|
||||||
|
auto origBuffSize = origBuf->getBufferSize();
|
||||||
|
if (Offset > origBuffSize)
|
||||||
|
Offset = origBuffSize;
|
||||||
|
|
||||||
|
auto newBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(
|
||||||
|
origBuffSize + 1, bufferIdentifier);
|
||||||
|
auto *pos = origBuf->getBufferStart() + Offset;
|
||||||
|
auto *newPos =
|
||||||
|
std::copy(origBuf->getBufferStart(), pos, newBuffer->getBufferStart());
|
||||||
|
*newPos = '\0';
|
||||||
|
std::copy(pos, origBuf->getBufferEnd(), newPos + 1);
|
||||||
|
|
||||||
|
return std::unique_ptr<llvm::MemoryBuffer>(newBuffer.release());
|
||||||
|
}
|
||||||
|
|
||||||
UIdent SwiftLangSupport::getUIDForDecl(const Decl *D, bool IsRef) {
|
UIdent SwiftLangSupport::getUIDForDecl(const Decl *D, bool IsRef) {
|
||||||
return UIdentVisitor(IsRef).visit(const_cast<Decl*>(D));
|
return UIdentVisitor(IsRef).visit(const_cast<Decl*>(D));
|
||||||
}
|
}
|
||||||
@@ -750,6 +771,71 @@ bool SwiftLangSupport::printAccessorUSR(const AbstractStorageDecl *D,
|
|||||||
return ide::printAccessorUSR(D, AccKind, OS);
|
return ide::printAccessorUSR(D, AccKind, OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwiftLangSupport::printMemberDeclDescription(const swift::ValueDecl *VD,
|
||||||
|
swift::Type baseTy,
|
||||||
|
bool usePlaceholder,
|
||||||
|
llvm::raw_ostream &OS) {
|
||||||
|
// Base name.
|
||||||
|
OS << VD->getBaseName().userFacingName();
|
||||||
|
|
||||||
|
// Parameters.
|
||||||
|
auto *M = VD->getModuleContext();
|
||||||
|
auto substMap = baseTy->getMemberSubstitutionMap(M, VD);
|
||||||
|
auto printSingleParam = [&](ParamDecl *param) {
|
||||||
|
auto paramTy = param->getInterfaceType();
|
||||||
|
|
||||||
|
// Label.
|
||||||
|
if (!param->getArgumentName().empty())
|
||||||
|
OS << param->getArgumentName() << ": ";
|
||||||
|
|
||||||
|
// InOut.
|
||||||
|
if (param->isInOut()) {
|
||||||
|
OS << "&";
|
||||||
|
paramTy = paramTy->getInOutObjectType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.
|
||||||
|
if (usePlaceholder)
|
||||||
|
OS << "<#T##";
|
||||||
|
|
||||||
|
if (auto substitutedTy = paramTy.subst(substMap))
|
||||||
|
paramTy = substitutedTy;
|
||||||
|
|
||||||
|
if (paramTy->hasError() && param->getTypeLoc().hasLocation()) {
|
||||||
|
// Fallback to 'TypeRepr' printing.
|
||||||
|
param->getTypeLoc().getTypeRepr()->print(OS);
|
||||||
|
} else {
|
||||||
|
paramTy.print(OS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usePlaceholder)
|
||||||
|
OS << "#>";
|
||||||
|
};
|
||||||
|
auto printParams = [&](const ParameterList *params) {
|
||||||
|
OS << '(';
|
||||||
|
bool isFirst = true;
|
||||||
|
for (auto param : params->getArray()) {
|
||||||
|
if (isFirst)
|
||||||
|
isFirst = false;
|
||||||
|
else
|
||||||
|
OS << ", ";
|
||||||
|
printSingleParam(param);
|
||||||
|
}
|
||||||
|
OS << ')';
|
||||||
|
};
|
||||||
|
if (auto EED = dyn_cast<EnumElementDecl>(VD)) {
|
||||||
|
if (auto params = EED->getParameterList())
|
||||||
|
printParams(params);
|
||||||
|
} else if (auto *FD = dyn_cast<FuncDecl>(VD)) {
|
||||||
|
if (auto params = FD->getParameters())
|
||||||
|
printParams(params);
|
||||||
|
} else if (isa<VarDecl>(VD)) {
|
||||||
|
// Var decl doesn't have parameters.
|
||||||
|
} else {
|
||||||
|
llvm_unreachable("Unsupported Decl kind for printMemberDeclDescription()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string SwiftLangSupport::resolvePathSymlinks(StringRef FilePath) {
|
std::string SwiftLangSupport::resolvePathSymlinks(StringRef FilePath) {
|
||||||
std::string InputPath = FilePath;
|
std::string InputPath = FilePath;
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|||||||
@@ -306,6 +306,13 @@ public:
|
|||||||
return CCCache;
|
return CCCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy a memory buffer inserting '0' at the position of \c origBuf.
|
||||||
|
// TODO: Share with code completion.
|
||||||
|
static std::unique_ptr<llvm::MemoryBuffer>
|
||||||
|
makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf,
|
||||||
|
unsigned &Offset,
|
||||||
|
const std::string bufferIdentifier);
|
||||||
|
|
||||||
static SourceKit::UIdent getUIDForDecl(const swift::Decl *D,
|
static SourceKit::UIdent getUIDForDecl(const swift::Decl *D,
|
||||||
bool IsRef = false);
|
bool IsRef = false);
|
||||||
static SourceKit::UIdent getUIDForExtensionOfDecl(const swift::Decl *D);
|
static SourceKit::UIdent getUIDForExtensionOfDecl(const swift::Decl *D);
|
||||||
@@ -381,6 +388,14 @@ public:
|
|||||||
static void
|
static void
|
||||||
printFullyAnnotatedGenericReq(const swift::GenericSignature *Sig,
|
printFullyAnnotatedGenericReq(const swift::GenericSignature *Sig,
|
||||||
llvm::raw_ostream &OS);
|
llvm::raw_ostream &OS);
|
||||||
|
|
||||||
|
/// Print 'description' or 'sourcetext' the given \p VD to \p OS. If
|
||||||
|
/// \p usePlaceholder is \c true, call argument positions are substituted with
|
||||||
|
/// a typed editor placeholders which is suitable for 'sourcetext'.
|
||||||
|
static void
|
||||||
|
printMemberDeclDescription(const swift::ValueDecl *VD, swift::Type baseTy,
|
||||||
|
bool usePlaceholder, llvm::raw_ostream &OS);
|
||||||
|
|
||||||
/// Tries to resolve the path to the real file-system path. If it fails it
|
/// Tries to resolve the path to the real file-system path. If it fails it
|
||||||
/// returns the original path;
|
/// returns the original path;
|
||||||
static std::string resolvePathSymlinks(StringRef FilePath);
|
static std::string resolvePathSymlinks(StringRef FilePath);
|
||||||
@@ -528,6 +543,11 @@ public:
|
|||||||
ArrayRef<const char *> Args,
|
ArrayRef<const char *> Args,
|
||||||
TypeContextInfoConsumer &Consumer) override;
|
TypeContextInfoConsumer &Consumer) override;
|
||||||
|
|
||||||
|
void getConformingMethodList(llvm::MemoryBuffer *inputBuf, unsigned Offset,
|
||||||
|
ArrayRef<const char *> Args,
|
||||||
|
ArrayRef<const char *> ExpectedTypes,
|
||||||
|
ConformingMethodListConsumer &Consumer) override;
|
||||||
|
|
||||||
void getStatistics(StatisticsReceiver) override;
|
void getStatistics(StatisticsReceiver) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -24,28 +24,6 @@ using namespace SourceKit;
|
|||||||
using namespace swift;
|
using namespace swift;
|
||||||
using namespace ide;
|
using namespace ide;
|
||||||
|
|
||||||
/// Copy a memory buffer inserting '0' at the position of \c origBuf.
|
|
||||||
// TODO: Share with code completion.
|
|
||||||
static std::unique_ptr<llvm::MemoryBuffer>
|
|
||||||
makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf,
|
|
||||||
unsigned &Offset,
|
|
||||||
const std::string bufferIdentifier) {
|
|
||||||
|
|
||||||
auto origBuffSize = origBuf->getBufferSize();
|
|
||||||
if (Offset > origBuffSize)
|
|
||||||
Offset = origBuffSize;
|
|
||||||
|
|
||||||
auto newBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(
|
|
||||||
origBuffSize + 1, bufferIdentifier);
|
|
||||||
auto *pos = origBuf->getBufferStart() + Offset;
|
|
||||||
auto *newPos =
|
|
||||||
std::copy(origBuf->getBufferStart(), pos, newBuffer->getBufferStart());
|
|
||||||
*newPos = '\0';
|
|
||||||
std::copy(pos, origBuf->getBufferEnd(), newPos + 1);
|
|
||||||
|
|
||||||
return std::unique_ptr<llvm::MemoryBuffer>(newBuffer.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang,
|
static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang,
|
||||||
llvm::MemoryBuffer *UnresolvedInputFile,
|
llvm::MemoryBuffer *UnresolvedInputFile,
|
||||||
unsigned Offset,
|
unsigned Offset,
|
||||||
@@ -56,8 +34,8 @@ static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang,
|
|||||||
Lang.resolvePathSymlinks(UnresolvedInputFile->getBufferIdentifier());
|
Lang.resolvePathSymlinks(UnresolvedInputFile->getBufferIdentifier());
|
||||||
|
|
||||||
auto origOffset = Offset;
|
auto origOffset = Offset;
|
||||||
auto newBuffer = makeCodeCompletionMemoryBuffer(UnresolvedInputFile, Offset,
|
auto newBuffer = SwiftLangSupport::makeCodeCompletionMemoryBuffer(
|
||||||
bufferIdentifier);
|
UnresolvedInputFile, Offset, bufferIdentifier);
|
||||||
|
|
||||||
CompilerInstance CI;
|
CompilerInstance CI;
|
||||||
PrintingDiagnosticConsumer PrintDiags;
|
PrintingDiagnosticConsumer PrintDiags;
|
||||||
@@ -107,12 +85,6 @@ static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print 'description' or 'sourcetext' the given \c VD to \c OS. If
|
|
||||||
/// \c usePlaceholder is true, call argument positions are substituted with
|
|
||||||
/// type editor placeholders which is suitable for 'sourcetext'.
|
|
||||||
static void printDeclDescription(llvm::raw_ostream &OS, Type baseTy,
|
|
||||||
ValueDecl *VD, bool usePlaceholder);
|
|
||||||
|
|
||||||
void SwiftLangSupport::getExpressionContextInfo(
|
void SwiftLangSupport::getExpressionContextInfo(
|
||||||
llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset,
|
llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset,
|
||||||
ArrayRef<const char *> Args,
|
ArrayRef<const char *> Args,
|
||||||
@@ -144,15 +116,15 @@ void SwiftLangSupport::getExpressionContextInfo(
|
|||||||
|
|
||||||
// Description.
|
// Description.
|
||||||
unsigned DescriptionBegin = SS.size();
|
unsigned DescriptionBegin = SS.size();
|
||||||
printDeclDescription(OS, Item.ExpectedTy, member,
|
SwiftLangSupport::printMemberDeclDescription(
|
||||||
/*usePlaceholder=*/false);
|
member, Item.ExpectedTy, /*usePlaceholder=*/false, OS);
|
||||||
unsigned DescriptionLength = SS.size() - DescriptionBegin;
|
unsigned DescriptionLength = SS.size() - DescriptionBegin;
|
||||||
StringRef Description(SS.begin() + DescriptionBegin, DescriptionLength);
|
StringRef Description(SS.begin() + DescriptionBegin, DescriptionLength);
|
||||||
|
|
||||||
// Sourcetext.
|
// Sourcetext.
|
||||||
unsigned SourceTextBegin = SS.size();
|
unsigned SourceTextBegin = SS.size();
|
||||||
printDeclDescription(OS, Item.ExpectedTy, member,
|
SwiftLangSupport::printMemberDeclDescription(
|
||||||
/*usePlaceholder=*/true);
|
member, Item.ExpectedTy, /*usePlaceholder=*/true, OS);
|
||||||
unsigned SourceTextLength = SS.size() - SourceTextBegin;
|
unsigned SourceTextLength = SS.size() - SourceTextBegin;
|
||||||
StringRef SourceText(SS.begin() + SourceTextBegin, SourceTextLength);
|
StringRef SourceText(SS.begin() + SourceTextBegin, SourceTextLength);
|
||||||
|
|
||||||
@@ -198,67 +170,3 @@ void SwiftLangSupport::getExpressionContextInfo(
|
|||||||
SKConsumer.failed(Error);
|
SKConsumer.failed(Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printDeclDescription(llvm::raw_ostream &OS, Type baseTy,
|
|
||||||
ValueDecl *VD, bool usePlaceholder) {
|
|
||||||
|
|
||||||
// Base name.
|
|
||||||
OS << VD->getBaseName().userFacingName();
|
|
||||||
|
|
||||||
// Parameters.
|
|
||||||
auto *M = VD->getModuleContext();
|
|
||||||
auto substMap = baseTy->getMemberSubstitutionMap(M, VD);
|
|
||||||
auto printSingleParam = [&](ParamDecl *param) {
|
|
||||||
auto paramTy = param->getInterfaceType();
|
|
||||||
|
|
||||||
// Label.
|
|
||||||
if (!param->getArgumentName().empty())
|
|
||||||
OS << param->getArgumentName() << ": ";
|
|
||||||
|
|
||||||
// InOut.
|
|
||||||
if (param->isInOut()) {
|
|
||||||
OS << "&";
|
|
||||||
paramTy = paramTy->getInOutObjectType();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type.
|
|
||||||
if (usePlaceholder)
|
|
||||||
OS << "<#T##";
|
|
||||||
|
|
||||||
if (auto substitutedTy = paramTy.subst(substMap))
|
|
||||||
paramTy = substitutedTy;
|
|
||||||
|
|
||||||
if (paramTy->hasError() && param->getTypeLoc().hasLocation()) {
|
|
||||||
// Fallback to 'TypeRepr' printing.
|
|
||||||
param->getTypeLoc().getTypeRepr()->print(OS);
|
|
||||||
} else {
|
|
||||||
paramTy.print(OS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usePlaceholder)
|
|
||||||
OS << "#>";
|
|
||||||
};
|
|
||||||
auto printParams = [&](ParameterList *params) {
|
|
||||||
OS << '(';
|
|
||||||
bool isFirst = true;
|
|
||||||
for (auto param : params->getArray()) {
|
|
||||||
if (isFirst)
|
|
||||||
isFirst = false;
|
|
||||||
else
|
|
||||||
OS << ", ";
|
|
||||||
printSingleParam(param);
|
|
||||||
}
|
|
||||||
OS << ')';
|
|
||||||
};
|
|
||||||
if (auto EED = dyn_cast<EnumElementDecl>(VD)) {
|
|
||||||
if (auto params = EED->getParameterList())
|
|
||||||
printParams(params);
|
|
||||||
} else if (auto *FD = dyn_cast<FuncDecl>(VD)) {
|
|
||||||
if (auto params = FD->getParameters())
|
|
||||||
printParams(params);
|
|
||||||
} else if (isa<VarDecl>(VD)) {
|
|
||||||
// Var decl doesn't have parameters.
|
|
||||||
} else {
|
|
||||||
llvm_unreachable("Invalid Decl type for context info implicit member");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
|
|||||||
.Case("complete.cache.ondisk", SourceKitRequest::CodeCompleteCacheOnDisk)
|
.Case("complete.cache.ondisk", SourceKitRequest::CodeCompleteCacheOnDisk)
|
||||||
.Case("complete.setpopularapi", SourceKitRequest::CodeCompleteSetPopularAPI)
|
.Case("complete.setpopularapi", SourceKitRequest::CodeCompleteSetPopularAPI)
|
||||||
.Case("typecontextinfo", SourceKitRequest::TypeContextInfo)
|
.Case("typecontextinfo", SourceKitRequest::TypeContextInfo)
|
||||||
|
.Case("conformingmethods", SourceKitRequest::ConformingMethodList)
|
||||||
.Case("cursor", SourceKitRequest::CursorInfo)
|
.Case("cursor", SourceKitRequest::CursorInfo)
|
||||||
.Case("related-idents", SourceKitRequest::RelatedIdents)
|
.Case("related-idents", SourceKitRequest::RelatedIdents)
|
||||||
.Case("syntax-map", SourceKitRequest::SyntaxMap)
|
.Case("syntax-map", SourceKitRequest::SyntaxMap)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ enum class SourceKitRequest {
|
|||||||
CodeCompleteCacheOnDisk,
|
CodeCompleteCacheOnDisk,
|
||||||
CodeCompleteSetPopularAPI,
|
CodeCompleteSetPopularAPI,
|
||||||
TypeContextInfo,
|
TypeContextInfo,
|
||||||
|
ConformingMethodList,
|
||||||
CursorInfo,
|
CursorInfo,
|
||||||
RangeInfo,
|
RangeInfo,
|
||||||
RelatedIdents,
|
RelatedIdents,
|
||||||
|
|||||||
@@ -564,6 +564,30 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) {
|
|||||||
sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
|
sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SourceKitRequest::ConformingMethodList:
|
||||||
|
sourcekitd_request_dictionary_set_uid(Req, KeyRequest,
|
||||||
|
RequestConformingMethodList);
|
||||||
|
sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset);
|
||||||
|
for (auto &Opt : Opts.RequestOptions) {
|
||||||
|
auto KeyValue = StringRef(Opt).split('=');
|
||||||
|
if (KeyValue.first == "expectedtypes") {
|
||||||
|
SmallVector<StringRef, 4> expectedTypeNames;
|
||||||
|
KeyValue.second.split(expectedTypeNames, ';');
|
||||||
|
|
||||||
|
auto typenames = sourcekitd_request_array_create(nullptr, 0);
|
||||||
|
for (auto &name : expectedTypeNames) {
|
||||||
|
std::string n = name;
|
||||||
|
sourcekitd_request_array_set_string(typenames, SOURCEKITD_ARRAY_APPEND, n.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcekitd_request_dictionary_set_value(Req, KeyExpectedTypes, typenames);
|
||||||
|
} else {
|
||||||
|
llvm::errs() << "invalid key '" << KeyValue.first << "' in -req-opts\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SourceKitRequest::CursorInfo:
|
case SourceKitRequest::CursorInfo:
|
||||||
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCursorInfo);
|
sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCursorInfo);
|
||||||
if (Opts.CollectActionables) {
|
if (Opts.CollectActionables) {
|
||||||
@@ -1013,6 +1037,7 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts,
|
|||||||
case SourceKitRequest::CodeCompleteCacheOnDisk:
|
case SourceKitRequest::CodeCompleteCacheOnDisk:
|
||||||
case SourceKitRequest::CodeCompleteSetPopularAPI:
|
case SourceKitRequest::CodeCompleteSetPopularAPI:
|
||||||
case SourceKitRequest::TypeContextInfo:
|
case SourceKitRequest::TypeContextInfo:
|
||||||
|
case SourceKitRequest::ConformingMethodList:
|
||||||
sourcekitd_response_description_dump_filedesc(Resp, STDOUT_FILENO);
|
sourcekitd_response_description_dump_filedesc(Resp, STDOUT_FILENO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -171,6 +171,11 @@ static sourcekitd_response_t typeContextInfo(llvm::MemoryBuffer *InputBuf,
|
|||||||
int64_t Offset,
|
int64_t Offset,
|
||||||
ArrayRef<const char *> Args);
|
ArrayRef<const char *> Args);
|
||||||
|
|
||||||
|
static sourcekitd_response_t
|
||||||
|
conformingMethodList(llvm::MemoryBuffer *InputBuf, int64_t Offset,
|
||||||
|
ArrayRef<const char *> Args,
|
||||||
|
ArrayRef<const char *> ExpectedTypes);
|
||||||
|
|
||||||
static sourcekitd_response_t
|
static sourcekitd_response_t
|
||||||
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf,
|
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf,
|
||||||
SKEditorConsumerOptions Opts, ArrayRef<const char *> Args);
|
SKEditorConsumerOptions Opts, ArrayRef<const char *> Args);
|
||||||
@@ -886,6 +891,21 @@ handleSemanticRequest(RequestDict Req,
|
|||||||
return Rec(typeContextInfo(InputBuf.get(), Offset, Args));
|
return Rec(typeContextInfo(InputBuf.get(), Offset, Args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ReqUID == RequestConformingMethodList) {
|
||||||
|
std::unique_ptr<llvm::MemoryBuffer> InputBuf =
|
||||||
|
getInputBufForRequest(SourceFile, SourceText, ErrBuf);
|
||||||
|
if (!InputBuf)
|
||||||
|
return Rec(createErrorRequestFailed(ErrBuf.c_str()));
|
||||||
|
int64_t Offset;
|
||||||
|
if (Req.getInt64(KeyOffset, Offset, /*isOptional=*/false))
|
||||||
|
return Rec(createErrorRequestInvalid("missing 'key.offset'"));
|
||||||
|
SmallVector<const char *, 8> ExpectedTypeNames;
|
||||||
|
if (Req.getStringArray(KeyExpectedTypes, ExpectedTypeNames, true))
|
||||||
|
return Rec(createErrorRequestInvalid("invalid 'key.expectedtypes'"));
|
||||||
|
return Rec(
|
||||||
|
conformingMethodList(InputBuf.get(), Offset, Args, ExpectedTypeNames));
|
||||||
|
}
|
||||||
|
|
||||||
if (!SourceFile.hasValue())
|
if (!SourceFile.hasValue())
|
||||||
return Rec(createErrorRequestInvalid("missing 'key.sourcefile'"));
|
return Rec(createErrorRequestInvalid("missing 'key.sourcefile'"));
|
||||||
|
|
||||||
@@ -2110,6 +2130,57 @@ static sourcekitd_response_t typeContextInfo(llvm::MemoryBuffer *InputBuf,
|
|||||||
return RespBuilder.createResponse();
|
return RespBuilder.createResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Conforming Method List
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static sourcekitd_response_t
|
||||||
|
conformingMethodList(llvm::MemoryBuffer *InputBuf, int64_t Offset,
|
||||||
|
ArrayRef<const char *> Args,
|
||||||
|
ArrayRef<const char *> ExpectedTypes) {
|
||||||
|
ResponseBuilder RespBuilder;
|
||||||
|
|
||||||
|
class Consumer : public ConformingMethodListConsumer {
|
||||||
|
ResponseBuilder::Dictionary SKResult;
|
||||||
|
Optional<std::string> ErrorDescription;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Consumer(ResponseBuilder Builder) : SKResult(Builder.getDictionary()) {}
|
||||||
|
|
||||||
|
void handleResult(const ConformingMethodListResult &Result) override {
|
||||||
|
SKResult.set(KeyTypeName, Result.TypeName);
|
||||||
|
SKResult.set(KeyTypeUsr, Result.TypeUSR);
|
||||||
|
auto members = SKResult.setArray(KeyMembers);
|
||||||
|
for (auto member : Result.Members) {
|
||||||
|
auto memberElem = members.appendDictionary();
|
||||||
|
memberElem.set(KeyName, member.Name);
|
||||||
|
memberElem.set(KeyTypeName, member.TypeName);
|
||||||
|
memberElem.set(KeyTypeUsr, member.TypeUSR);
|
||||||
|
memberElem.set(KeyDescription, member.Description);
|
||||||
|
memberElem.set(KeySourceText, member.SourceText);
|
||||||
|
if (!member.DocBrief.empty())
|
||||||
|
memberElem.set(KeyDocBrief, member.DocBrief);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void failed(StringRef ErrDescription) override {
|
||||||
|
ErrorDescription = ErrDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isError() const { return ErrorDescription.hasValue(); }
|
||||||
|
const char *getErrorDescription() const {
|
||||||
|
return ErrorDescription->c_str();
|
||||||
|
}
|
||||||
|
} Consumer(RespBuilder);
|
||||||
|
|
||||||
|
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
|
||||||
|
Lang.getConformingMethodList(InputBuf, Offset, Args, ExpectedTypes, Consumer);
|
||||||
|
|
||||||
|
if (Consumer.isError())
|
||||||
|
return createErrorRequestFailed(Consumer.getErrorDescription());
|
||||||
|
return RespBuilder.createResponse();
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Editor
|
// Editor
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
||||||
#include "swift/IDE/CodeCompletion.h"
|
#include "swift/IDE/CodeCompletion.h"
|
||||||
#include "swift/IDE/CommentConversion.h"
|
#include "swift/IDE/CommentConversion.h"
|
||||||
|
#include "swift/IDE/ConformingMethodList.h"
|
||||||
#include "swift/IDE/ModuleInterfacePrinting.h"
|
#include "swift/IDE/ModuleInterfacePrinting.h"
|
||||||
#include "swift/IDE/REPLCodeCompletion.h"
|
#include "swift/IDE/REPLCodeCompletion.h"
|
||||||
#include "swift/IDE/SourceEntityWalker.h"
|
#include "swift/IDE/SourceEntityWalker.h"
|
||||||
@@ -101,6 +102,7 @@ enum class ActionType {
|
|||||||
ReconstructType,
|
ReconstructType,
|
||||||
Range,
|
Range,
|
||||||
TypeContextInfo,
|
TypeContextInfo,
|
||||||
|
ConformingMethodList,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NullDebuggerClient : public DebuggerClient {
|
class NullDebuggerClient : public DebuggerClient {
|
||||||
@@ -225,7 +227,10 @@ Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None),
|
|||||||
"Print indexed symbol information"),
|
"Print indexed symbol information"),
|
||||||
clEnumValN(ActionType::TypeContextInfo,
|
clEnumValN(ActionType::TypeContextInfo,
|
||||||
"type-context-info",
|
"type-context-info",
|
||||||
"Perform expression context info analysis")));
|
"Perform expression context info analysis"),
|
||||||
|
clEnumValN(ActionType::ConformingMethodList,
|
||||||
|
"conforming-methods",
|
||||||
|
"Perform conforming method analysis for expression")));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string>
|
static llvm::cl::opt<std::string>
|
||||||
SourceFilename("source-filename", llvm::cl::desc("Name of the source file"),
|
SourceFilename("source-filename", llvm::cl::desc("Name of the source file"),
|
||||||
@@ -419,6 +424,13 @@ DebugClientDiscriminator("debug-client-discriminator",
|
|||||||
llvm::cl::desc("A discriminator to prefer in lookups"),
|
llvm::cl::desc("A discriminator to prefer in lookups"),
|
||||||
llvm::cl::cat(Category));
|
llvm::cl::cat(Category));
|
||||||
|
|
||||||
|
// '-conforming-methods' options.
|
||||||
|
|
||||||
|
static llvm::cl::list<std::string>
|
||||||
|
ConformingMethodListExpectedTypes("conforming-methods-expected-types",
|
||||||
|
llvm::cl::desc("Set expected types for comforming method list"),
|
||||||
|
llvm::cl::cat(Category));
|
||||||
|
|
||||||
// '-syntax-coloring' options.
|
// '-syntax-coloring' options.
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
static llvm::cl::opt<bool>
|
||||||
@@ -748,6 +760,70 @@ static int doTypeContextInfo(const CompilerInvocation &InitInvok,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
doConformingMethodList(const CompilerInvocation &InitInvok,
|
||||||
|
StringRef SourceFilename, StringRef SecondSourceFileName,
|
||||||
|
StringRef CodeCompletionToken,
|
||||||
|
bool CodeCompletionDiagnostics,
|
||||||
|
const std::vector<std::string> expectedTypeNames) {
|
||||||
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
|
||||||
|
llvm::MemoryBuffer::getFile(SourceFilename);
|
||||||
|
if (!FileBufOrErr) {
|
||||||
|
llvm::errs() << "error opening input file: "
|
||||||
|
<< FileBufOrErr.getError().message() << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Offset;
|
||||||
|
|
||||||
|
std::unique_ptr<llvm::MemoryBuffer> CleanFile(removeCodeCompletionTokens(
|
||||||
|
FileBufOrErr.get().get(), CodeCompletionToken, &Offset));
|
||||||
|
|
||||||
|
if (Offset == ~0U) {
|
||||||
|
llvm::errs() << "could not find code completion token \""
|
||||||
|
<< CodeCompletionToken << "\"\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
llvm::outs() << "found code completion token " << CodeCompletionToken
|
||||||
|
<< " at offset " << Offset << "\n";
|
||||||
|
llvm::errs() << "found code completion token " << CodeCompletionToken
|
||||||
|
<< " at offset " << Offset << "\n";
|
||||||
|
|
||||||
|
CompilerInvocation Invocation(InitInvok);
|
||||||
|
|
||||||
|
Invocation.setCodeCompletionPoint(CleanFile.get(), Offset);
|
||||||
|
|
||||||
|
SmallVector<const char *, 4> typeNames;
|
||||||
|
for (auto &name : expectedTypeNames)
|
||||||
|
typeNames.push_back(name.c_str());
|
||||||
|
|
||||||
|
// Create a CodeCompletionConsumer.
|
||||||
|
std::unique_ptr<ide::ConformingMethodListConsumer> Consumer(
|
||||||
|
new ide::PrintingConformingMethodListConsumer(llvm::outs()));
|
||||||
|
|
||||||
|
// Create a factory for code completion callbacks that will feed the
|
||||||
|
// Consumer.
|
||||||
|
std::unique_ptr<CodeCompletionCallbacksFactory> callbacksFactory(
|
||||||
|
ide::makeConformingMethodListCallbacksFactory(typeNames, *Consumer));
|
||||||
|
|
||||||
|
Invocation.setCodeCompletionFactory(callbacksFactory.get());
|
||||||
|
if (!SecondSourceFileName.empty()) {
|
||||||
|
Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(
|
||||||
|
SecondSourceFileName);
|
||||||
|
}
|
||||||
|
CompilerInstance CI;
|
||||||
|
|
||||||
|
PrintingDiagnosticConsumer PrintDiags;
|
||||||
|
if (CodeCompletionDiagnostics) {
|
||||||
|
// Display diagnostics to stderr.
|
||||||
|
CI.addDiagnosticConsumer(&PrintDiags);
|
||||||
|
}
|
||||||
|
if (CI.setup(Invocation))
|
||||||
|
return 1;
|
||||||
|
CI.performSema();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int doCodeCompletion(const CompilerInvocation &InitInvok,
|
static int doCodeCompletion(const CompilerInvocation &InitInvok,
|
||||||
StringRef SourceFilename,
|
StringRef SourceFilename,
|
||||||
StringRef SecondSourceFileName,
|
StringRef SecondSourceFileName,
|
||||||
@@ -3277,6 +3353,19 @@ int main(int argc, char *argv[]) {
|
|||||||
options::CodeCompletionDiagnostics);
|
options::CodeCompletionDiagnostics);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ActionType::ConformingMethodList:
|
||||||
|
if (options::CodeCompletionToken.empty()) {
|
||||||
|
llvm::errs() << "token name required\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ExitCode = doConformingMethodList(InitInvok,
|
||||||
|
options::SourceFilename,
|
||||||
|
options::SecondSourceFilename,
|
||||||
|
options::CodeCompletionToken,
|
||||||
|
options::CodeCompletionDiagnostics,
|
||||||
|
options::ConformingMethodListExpectedTypes);
|
||||||
|
break;
|
||||||
|
|
||||||
case ActionType::SyntaxColoring:
|
case ActionType::SyntaxColoring:
|
||||||
ExitCode = doSyntaxColoring(InitInvok,
|
ExitCode = doSyntaxColoring(InitInvok,
|
||||||
options::SourceFilename,
|
options::SourceFilename,
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ UID_KEYS = [
|
|||||||
KEY('CompileID', 'key.compileid'),
|
KEY('CompileID', 'key.compileid'),
|
||||||
KEY('CompilerArgsString', 'key.compilerargs-string'),
|
KEY('CompilerArgsString', 'key.compilerargs-string'),
|
||||||
KEY('ImplicitMembers', 'key.implicitmembers'),
|
KEY('ImplicitMembers', 'key.implicitmembers'),
|
||||||
|
KEY('ExpectedTypes', 'key.expectedtypes'),
|
||||||
|
KEY('Members', 'key.members'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -182,6 +184,7 @@ UID_REQUESTS = [
|
|||||||
'source.request.codecomplete.setpopularapi'),
|
'source.request.codecomplete.setpopularapi'),
|
||||||
REQUEST('CodeCompleteSetCustom', 'source.request.codecomplete.setcustom'),
|
REQUEST('CodeCompleteSetCustom', 'source.request.codecomplete.setcustom'),
|
||||||
REQUEST('TypeContextInfo', 'source.request.typecontextinfo'),
|
REQUEST('TypeContextInfo', 'source.request.typecontextinfo'),
|
||||||
|
REQUEST('ConformingMethodList', 'source.request.conformingmethods'),
|
||||||
REQUEST('CursorInfo', 'source.request.cursorinfo'),
|
REQUEST('CursorInfo', 'source.request.cursorinfo'),
|
||||||
REQUEST('RangeInfo', 'source.request.rangeinfo'),
|
REQUEST('RangeInfo', 'source.request.rangeinfo'),
|
||||||
REQUEST('RelatedIdents', 'source.request.relatedidents'),
|
REQUEST('RelatedIdents', 'source.request.relatedidents'),
|
||||||
|
|||||||
Reference in New Issue
Block a user