1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
//===--- UnresolvedMemberCodeCompletion.cpp -------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 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/UnresolvedMemberCompletion.h"
#include "swift/IDE/CodeCompletion.h"
#include "swift/IDE/CompletionLookup.h"
#include "swift/Sema/CompletionContextFinder.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/IDETypeChecking.h"
using namespace swift;
using namespace swift::constraints;
using namespace swift::ide;
bool UnresolvedMemberTypeCheckCompletionCallback::Result::tryMerge(
const Result &Other, DeclContext *DC) {
auto expectedTy = tryMergeBaseTypeForCompletionLookup(ExpectedTy,
Other.ExpectedTy, DC);
if (!expectedTy)
return false;
ExpectedTy = expectedTy;
IsImpliedResult |= Other.IsImpliedResult;
IsInAsyncContext |= Other.IsInAsyncContext;
return true;
}
void UnresolvedMemberTypeCheckCompletionCallback::addExprResult(
const Result &Res) {
for (auto idx : indices(ExprResults)) {
if (ExprResults[idx].tryMerge(Res, DC))
return;
}
ExprResults.push_back(Res);
}
void UnresolvedMemberTypeCheckCompletionCallback::sawSolutionImpl(
const constraints::Solution &S) {
Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);
bool IsAsync = isContextAsync(S, DC);
// If the type couldn't be determined (e.g. because there isn't any context
// to derive it from), let's not attempt to do a lookup since it wouldn't
// produce any useful results anyway.
if (ExpectedTy) {
bool IsImpliedResult = isImpliedResult(S, CompletionExpr);
Result Res = {ExpectedTy, IsImpliedResult, IsAsync};
addExprResult(Res);
}
if (auto PatternType = getPatternMatchType(S, CompletionExpr)) {
auto IsEqual = [&](const Result &R) {
return R.ExpectedTy->isEqual(PatternType);
};
if (!llvm::any_of(EnumPatternTypes, IsEqual)) {
EnumPatternTypes.push_back(
{PatternType, /*isImpliedResult=*/false, IsAsync});
}
}
}
void UnresolvedMemberTypeCheckCompletionCallback::collectResults(
DeclContext *DC, SourceLoc DotLoc,
ide::CodeCompletionContext &CompletionCtx) {
ASTContext &Ctx = DC->getASTContext();
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
&CompletionCtx);
assert(DotLoc.isValid());
Lookup.setHaveDot(DotLoc);
Lookup.shouldCheckForDuplicates(ExprResults.size() + EnumPatternTypes.size() >
1);
// Get the canonical versions of the top-level types
SmallPtrSet<CanType, 4> originalTypes;
for (auto &Result : ExprResults)
originalTypes.insert(Result.ExpectedTy->getCanonicalType());
for (auto &Result : ExprResults) {
Lookup.setExpectedTypes({Result.ExpectedTy}, Result.IsImpliedResult,
/*expectsNonVoid*/ true);
Lookup.setIdealExpectedType(Result.ExpectedTy);
Lookup.setCanCurrDeclContextHandleAsync(Result.IsInAsyncContext);
// For optional types, also get members of the unwrapped type if it's not
// already equivalent to one of the top-level types. Handling it via the top
// level type and not here ensures we give the correct type relation
// (identical, rather than convertible).
if (Result.ExpectedTy->getOptionalObjectType()) {
Type Unwrapped = Result.ExpectedTy->lookThroughAllOptionalTypes();
if (originalTypes.insert(Unwrapped->getCanonicalType()).second)
Lookup.getUnresolvedMemberCompletions(Unwrapped);
}
Lookup.getUnresolvedMemberCompletions(Result.ExpectedTy);
}
// The type context that is being used for global results.
ExpectedTypeContext UnifiedTypeContext;
UnifiedTypeContext.setPreferNonVoid(true);
bool UnifiedCanHandleAsync = false;
// Offer completions when interpreting the pattern match as an
// EnumElementPattern.
for (auto &Result : EnumPatternTypes) {
Type Ty = Result.ExpectedTy;
Lookup.setExpectedTypes({Ty}, /*isImpliedResult=*/false,
/*expectsNonVoid=*/true);
Lookup.setIdealExpectedType(Ty);
Lookup.setCanCurrDeclContextHandleAsync(Result.IsInAsyncContext);
// We can pattern match MyEnum against Optional<MyEnum>
if (Ty->getOptionalObjectType()) {
Type Unwrapped = Ty->lookThroughAllOptionalTypes();
Lookup.getEnumElementPatternCompletions(Unwrapped);
}
Lookup.getEnumElementPatternCompletions(Ty);
UnifiedTypeContext.merge(*Lookup.getExpectedTypeContext());
UnifiedCanHandleAsync |= Result.IsInAsyncContext;
}
collectCompletionResults(CompletionCtx, Lookup, DC, UnifiedTypeContext,
UnifiedCanHandleAsync);
}
|