mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[SourceKit] Move invocation of code completion second pass for ConformingMethodList from SoruceKit to CompletionInstance
This commit is contained in:
@@ -32,80 +32,125 @@ translateConformingMethodListOptions(OptionsDictionary &from,
|
||||
// ConformingMethodList doesn't receive any options at this point.
|
||||
}
|
||||
|
||||
/// The results returned from \c swiftConformingMethodListImpl through the
|
||||
/// callback.
|
||||
struct ConformingMethodListImplResult {
|
||||
/// The actual results. If \c nullptr, no results were found.
|
||||
const ide::ConformingMethodListResult *Result;
|
||||
/// Whether an AST was reused for the completion.
|
||||
bool DidReuseAST;
|
||||
};
|
||||
void deliverResults(SourceKit::ConformingMethodListConsumer &SKConsumer,
|
||||
CancellableResult<ConformingMethodListResults> Result) {
|
||||
switch (Result.getKind()) {
|
||||
case CancellableResultKind::Success: {
|
||||
SKConsumer.setReusingASTContext(Result->DidReuseAST);
|
||||
|
||||
static void swiftConformingMethodListImpl(
|
||||
SwiftLangSupport &Lang, llvm::MemoryBuffer *UnresolvedInputFile,
|
||||
unsigned Offset, ArrayRef<const char *> Args,
|
||||
ArrayRef<const char *> ExpectedTypeNames,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
|
||||
llvm::function_ref<void(CancellableResult<ConformingMethodListImplResult>)>
|
||||
Callback) {
|
||||
assert(Callback && "Must provide callback to receive results");
|
||||
|
||||
using ResultType = CancellableResult<ConformingMethodListImplResult>;
|
||||
|
||||
struct ConsumerToCallbackAdapter
|
||||
: public swift::ide::ConformingMethodListConsumer {
|
||||
bool ReusingASTContext;
|
||||
llvm::function_ref<void(ResultType)> Callback;
|
||||
bool HandleResultWasCalled = false;
|
||||
|
||||
ConsumerToCallbackAdapter(bool ReusingASTContext,
|
||||
llvm::function_ref<void(ResultType)> Callback)
|
||||
: ReusingASTContext(ReusingASTContext), Callback(Callback) {}
|
||||
|
||||
void handleResult(const ide::ConformingMethodListResult &result) override {
|
||||
HandleResultWasCalled = true;
|
||||
Callback(ResultType::success({&result, ReusingASTContext}));
|
||||
if (!Result->Result) {
|
||||
// If we have no results, don't call SKConsumer.handleResult which causes
|
||||
// empty results to be delivered.
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
Lang.performCompletionLikeOperation(
|
||||
UnresolvedInputFile, Offset, Args, FileSystem,
|
||||
[&](CancellableResult<CompletionInstanceResult> Result) {
|
||||
switch (Result.getKind()) {
|
||||
case CancellableResultKind::Success: {
|
||||
ConsumerToCallbackAdapter Consumer(Result->DidReuseAST, Callback);
|
||||
SmallString<512> SS;
|
||||
llvm::raw_svector_ostream OS(SS);
|
||||
|
||||
// Create a factory for code completion callbacks that will feed the
|
||||
// Consumer.
|
||||
std::unique_ptr<CodeCompletionCallbacksFactory> callbacksFactory(
|
||||
ide::makeConformingMethodListCallbacksFactory(ExpectedTypeNames,
|
||||
Consumer));
|
||||
unsigned TypeNameBegin = SS.size();
|
||||
Result->Result->ExprType.print(OS);
|
||||
unsigned TypeNameLength = SS.size() - TypeNameBegin;
|
||||
|
||||
if (!Result->DidFindCodeCompletionToken) {
|
||||
Callback(ResultType::success(
|
||||
{/*Results=*/nullptr, Result->DidReuseAST}));
|
||||
return;
|
||||
}
|
||||
unsigned TypeUSRBegin = SS.size();
|
||||
SwiftLangSupport::printTypeUSR(Result->Result->ExprType, OS);
|
||||
unsigned TypeUSRLength = SS.size() - TypeUSRBegin;
|
||||
|
||||
performCodeCompletionSecondPass(*Result->CI.getCodeCompletionFile(),
|
||||
*callbacksFactory);
|
||||
if (!Consumer.HandleResultWasCalled) {
|
||||
// If we didn't receive a handleResult call from the second pass,
|
||||
// we didn't receive any results. To make sure Callback gets called
|
||||
// exactly once, call it manually with no results here.
|
||||
Callback(ResultType::success(
|
||||
{/*Results=*/nullptr, Result->DidReuseAST}));
|
||||
}
|
||||
break;
|
||||
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->Result->Members) {
|
||||
Members.emplace_back();
|
||||
auto &memberElem = Members.back();
|
||||
|
||||
auto funcTy = cast<FuncDecl>(member)->getMethodInterfaceType();
|
||||
funcTy = Result->Result->ExprType->getTypeOfMember(
|
||||
Result->Result->DC->getParentModule(), member, funcTy);
|
||||
auto resultTy = funcTy->castTo<FunctionType>()->getResult();
|
||||
|
||||
// Name.
|
||||
memberElem.DeclNameBegin = SS.size();
|
||||
member->getName().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->Result->ExprType, /*usePlaceholder=*/false, OS);
|
||||
memberElem.DescriptionLength = SS.size() - memberElem.DescriptionBegin;
|
||||
|
||||
// Sourcetext.
|
||||
memberElem.SourceTextBegin = SS.size();
|
||||
SwiftLangSupport::printMemberDeclDescription(
|
||||
member, Result->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);
|
||||
}
|
||||
case CancellableResultKind::Failure:
|
||||
Callback(ResultType::failure(Result.getError()));
|
||||
break;
|
||||
case CancellableResultKind::Cancelled:
|
||||
Callback(ResultType::cancelled());
|
||||
break;
|
||||
}
|
||||
});
|
||||
} 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);
|
||||
break;
|
||||
}
|
||||
case CancellableResultKind::Failure:
|
||||
SKConsumer.failed(Result.getError());
|
||||
break;
|
||||
case CancellableResultKind::Cancelled:
|
||||
SKConsumer.cancelled();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftLangSupport::getConformingMethodList(
|
||||
@@ -119,151 +164,24 @@ void SwiftLangSupport::getConformingMethodList(
|
||||
// FIXME: the use of None as primary file is to match the fact we do not read
|
||||
// the document contents using the editor documents infrastructure.
|
||||
auto fileSystem = getFileSystem(vfsOptions, /*primaryFile=*/None, error);
|
||||
if (!fileSystem)
|
||||
if (!fileSystem) {
|
||||
return SKConsumer.failed(error);
|
||||
}
|
||||
|
||||
ConformingMethodList::Options options;
|
||||
if (optionsDict) {
|
||||
translateConformingMethodListOptions(*optionsDict, options);
|
||||
}
|
||||
|
||||
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) override {
|
||||
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->getName().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);
|
||||
}
|
||||
|
||||
void setReusingASTContext(bool flag) {
|
||||
SKConsumer.setReusingASTContext(flag);
|
||||
}
|
||||
} Consumer(SKConsumer);
|
||||
|
||||
swiftConformingMethodListImpl(
|
||||
*this, UnresolvedInputFile, Offset, Args, ExpectedTypeNames, fileSystem,
|
||||
[&](CancellableResult<ConformingMethodListImplResult> Result) {
|
||||
switch (Result.getKind()) {
|
||||
case CancellableResultKind::Success: {
|
||||
if (Result->Result) {
|
||||
Consumer.handleResult(*Result->Result);
|
||||
}
|
||||
// If we didn't receive any result, don't call handleResult on
|
||||
// Consumer to deliver empty results.
|
||||
Consumer.setReusingASTContext(Result->DidReuseAST);
|
||||
break;
|
||||
}
|
||||
case CancellableResultKind::Failure:
|
||||
SKConsumer.failed(Result.getError());
|
||||
break;
|
||||
case CancellableResultKind::Cancelled:
|
||||
SKConsumer.cancelled();
|
||||
break;
|
||||
}
|
||||
performWithParamsToCompletionLikeOperation(
|
||||
UnresolvedInputFile, Offset, Args, fileSystem,
|
||||
[&](CancellableResult<CompletionLikeOperationParams> ParmsResult) {
|
||||
ParmsResult.mapAsync<ConformingMethodListResults>(
|
||||
[&](auto &Params, auto DeliverTransformed) {
|
||||
getCompletionInstance()->conformingMethodList(
|
||||
Params.Invocation, Args, fileSystem, Params.completionBuffer,
|
||||
Offset, Params.DiagC, ExpectedTypeNames, DeliverTransformed);
|
||||
},
|
||||
[&](auto Result) { deliverResults(SKConsumer, Result); });
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user