Skip to content

Commit a704547

Browse files
committed
[SourceKit] Compute code completion type relation when wrapping a ContextFreeCodeCompletionResult in a CodeCompletionResult
1 parent df73082 commit a704547

File tree

9 files changed

+322
-170
lines changed

9 files changed

+322
-170
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 162 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#ifndef SWIFT_IDE_CODECOMPLETION_H
1414
#define SWIFT_IDE_CODECOMPLETION_H
1515

16+
#include "swift/AST/ASTDemangler.h"
1617
#include "swift/AST/Identifier.h"
18+
#include "swift/AST/USRGeneration.h"
1719
#include "swift/Basic/Debug.h"
1820
#include "swift/Basic/LLVM.h"
1921
#include "swift/Basic/OptionSet.h"
@@ -697,7 +699,94 @@ enum class CodeCompletionResultKind : uint8_t {
697699
MAX_VALUE = BuiltinOperator
698700
};
699701

700-
class CodeCompletionResult;
702+
/// The type returned by a code completion item. It is canonicalized and can be
703+
/// instantiated in different \c ASTContexts.
704+
class CodeCompletionResultType {
705+
706+
/// The USR of the type. Used to re-instantiate the type in different \c
707+
/// ASTContexts.
708+
std::string USR;
709+
710+
/// If a type has already been computed from the USR, it is cached here.
711+
Type Ty;
712+
713+
/// The \c ASTContext in which \c Ty lives. Must be stored separately from
714+
/// \c Ty because the \c ASTContext in which \c Ty lives might get destroyed,
715+
/// thus making the pointer inside \c Ty invalid.
716+
ASTContext *ContextOfTy;
717+
718+
/// Maps USRs to \c CodeCompletionResultTypes that have already been
719+
/// constructed.
720+
static llvm::StringMap<CodeCompletionResultType *> USRCache;
721+
722+
/// Maps Types to \c CodeCompletionResultTypes that have already been
723+
/// constructed.
724+
static llvm::DenseMap<Type, CodeCompletionResultType *> TypeCache;
725+
726+
CodeCompletionResultType(StringRef USR) : USR(USR) {}
727+
728+
public:
729+
/// Create an \c CodeCompletionResultType from an \c ASTContext's \c Type.
730+
static CodeCompletionResultType *fromType(Type Ty) {
731+
auto ResFromType = TypeCache.find(Ty);
732+
if (ResFromType != TypeCache.end()) {
733+
return ResFromType->second;
734+
}
735+
CodeCompletionResultType *Res;
736+
// FIXME: We can't compute USRs for archetypes. If the type contains an
737+
// archetype, create a new CodeCompletionResultType so that multiple
738+
// archetypes aren't unified to the same ASTContextIndependent type.
739+
// Once we round-trip via the USR, this will produce a null type.
740+
if (Ty && !Ty->hasArchetype()) {
741+
SmallString<32> USR;
742+
llvm::raw_svector_ostream OS(USR);
743+
printTypeUSR(Ty, OS);
744+
Res = CodeCompletionResultType::fromUSR(USR);
745+
} else {
746+
Res = new CodeCompletionResultType("");
747+
}
748+
// We already know the Type. Cache it so it doesn't have to be recomputed.
749+
Res->Ty = Ty;
750+
if (Ty) {
751+
Res->ContextOfTy = &Ty->getASTContext();
752+
} else {
753+
Res->ContextOfTy = nullptr;
754+
}
755+
756+
TypeCache[Ty] = Res;
757+
758+
return Res;
759+
}
760+
761+
/// Create a type from a USR. The USR will only get demangled once a \c Type
762+
/// inside an \c ASTContext is requested using \c getType.
763+
static CodeCompletionResultType *fromUSR(StringRef USR) {
764+
auto ResFromUSR = USRCache.find(USR);
765+
if (ResFromUSR != USRCache.end()) {
766+
return ResFromUSR->second;
767+
}
768+
auto Res = new CodeCompletionResultType(USR);
769+
770+
USRCache[USR] = Res;
771+
return Res;
772+
}
773+
774+
/// Return the \c Type within the given \p Ctx.
775+
Type getType(ASTContext &Ctx) {
776+
if (!Ty || ContextOfTy != &Ctx) {
777+
if (USR.empty()) {
778+
Ty = Type();
779+
} else {
780+
Ty = Demangle::getTypeForMangling(Ctx, USR);
781+
}
782+
}
783+
return Ty;
784+
}
785+
786+
/// Return the USR of this type, which identifies the type independent of the
787+
/// \c ASTContext.
788+
StringRef getUSR() const { return USR; }
789+
};
701790

702791
/// The parts of a \c CodeCompletionResult that are not dependent on the context
703792
/// it appears in and can thus be cached.
@@ -710,6 +799,13 @@ class ContextFreeCodeCompletionResult {
710799
StringRef ModuleName;
711800
StringRef BriefDocComment;
712801
ArrayRef<StringRef> AssociatedUSRs;
802+
/// The type of the element produced by the expression. Can be
803+
/// - \c nullptr if the completion result doesn't produce something that's
804+
/// valid inside an expression, e.g. a keyword
805+
/// - A null type if the completion result produces something that's valid
806+
/// inside an expression but the result type isn't known
807+
/// - A proper type if the type produced by this completion result is known.
808+
CodeCompletionResultType *ResultType;
713809

714810
ContextFreeNotRecommendedReason NotRecommended;
715811
CodeCompletionDiagnosticSeverity DiagnosticSeverity : 3;
@@ -733,14 +829,16 @@ class ContextFreeCodeCompletionResult {
733829
CodeCompletionOperatorKind KnownOperatorKind, bool IsSystem,
734830
CodeCompletionString *CompletionString, StringRef ModuleName,
735831
StringRef BriefDocComment, ArrayRef<StringRef> AssociatedUSRs,
832+
CodeCompletionResultType *ResultType,
736833
ContextFreeNotRecommendedReason NotRecommended,
737834
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
738835
StringRef DiagnosticMessage)
739836
: Kind(Kind), AssociatedKind(AssociatedKind),
740837
KnownOperatorKind(KnownOperatorKind), IsSystem(IsSystem),
741838
CompletionString(CompletionString), ModuleName(ModuleName),
742839
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
743-
NotRecommended(NotRecommended), DiagnosticSeverity(DiagnosticSeverity),
840+
ResultType(ResultType), NotRecommended(NotRecommended),
841+
DiagnosticSeverity(DiagnosticSeverity),
744842
DiagnosticMessage(DiagnosticMessage) {
745843
assert((NotRecommended == ContextFreeNotRecommendedReason::None) ==
746844
(DiagnosticSeverity == CodeCompletionDiagnosticSeverity::None) &&
@@ -766,13 +864,14 @@ class ContextFreeCodeCompletionResult {
766864
ContextFreeCodeCompletionResult(
767865
CodeCompletionResultKind Kind, CodeCompletionString *CompletionString,
768866
CodeCompletionOperatorKind KnownOperatorKind, StringRef BriefDocComment,
867+
CodeCompletionResultType *ResultType,
769868
ContextFreeNotRecommendedReason NotRecommended,
770869
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
771870
StringRef DiagnosticMessage)
772871
: ContextFreeCodeCompletionResult(
773872
Kind, /*AssociatedKind=*/0, KnownOperatorKind,
774873
/*IsSystem=*/false, CompletionString, /*ModuleName=*/"",
775-
BriefDocComment, /*AssociatedUSRs=*/{}, NotRecommended,
874+
BriefDocComment, /*AssociatedUSRs=*/{}, ResultType, NotRecommended,
776875
DiagnosticSeverity, DiagnosticMessage) {}
777876

778877
/// Constructs a \c Keyword result.
@@ -782,12 +881,14 @@ class ContextFreeCodeCompletionResult {
782881
/// same \c CodeCompletionResultSink as the result itself.
783882
ContextFreeCodeCompletionResult(CodeCompletionKeywordKind Kind,
784883
CodeCompletionString *CompletionString,
785-
StringRef BriefDocComment)
884+
StringRef BriefDocComment,
885+
CodeCompletionResultType *ResultType)
786886
: ContextFreeCodeCompletionResult(
787887
CodeCompletionResultKind::Keyword, static_cast<uint8_t>(Kind),
788888
CodeCompletionOperatorKind::None, /*IsSystem=*/false,
789889
CompletionString, /*ModuleName=*/"", BriefDocComment,
790-
/*AssociatedUSRs=*/{}, ContextFreeNotRecommendedReason::None,
890+
/*AssociatedUSRs=*/{}, ResultType,
891+
ContextFreeNotRecommendedReason::None,
791892
CodeCompletionDiagnosticSeverity::None, /*DiagnosticMessage=*/"") {}
792893

793894
/// Constructs a \c Literal result.
@@ -796,13 +897,15 @@ class ContextFreeCodeCompletionResult {
796897
/// result, typically by storing them in the same \c CodeCompletionResultSink
797898
/// as the result itself.
798899
ContextFreeCodeCompletionResult(CodeCompletionLiteralKind LiteralKind,
799-
CodeCompletionString *CompletionString)
900+
CodeCompletionString *CompletionString,
901+
CodeCompletionResultType *ResultType)
800902
: ContextFreeCodeCompletionResult(
801903
CodeCompletionResultKind::Literal,
802904
static_cast<uint8_t>(LiteralKind), CodeCompletionOperatorKind::None,
803905
/*IsSystem=*/false, CompletionString, /*ModuleName=*/"",
804906
/*BriefDocComment=*/"",
805-
/*AssociatedUSRs=*/{}, ContextFreeNotRecommendedReason::None,
907+
/*AssociatedUSRs=*/{}, ResultType,
908+
ContextFreeNotRecommendedReason::None,
806909
CodeCompletionDiagnosticSeverity::None, /*DiagnosticMessage=*/"") {}
807910

808911
/// Constructs a \c Declaration result.
@@ -813,7 +916,7 @@ class ContextFreeCodeCompletionResult {
813916
ContextFreeCodeCompletionResult(
814917
CodeCompletionString *CompletionString, const Decl *AssociatedDecl,
815918
StringRef ModuleName, StringRef BriefDocComment,
816-
ArrayRef<StringRef> AssociatedUSRs,
919+
ArrayRef<StringRef> AssociatedUSRs, CodeCompletionResultType *ResultType,
817920
ContextFreeNotRecommendedReason NotRecommended,
818921
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
819922
StringRef DiagnosticMessage)
@@ -822,7 +925,7 @@ class ContextFreeCodeCompletionResult {
822925
static_cast<uint8_t>(getCodeCompletionDeclKind(AssociatedDecl)),
823926
CodeCompletionOperatorKind::None, getDeclIsSystem(AssociatedDecl),
824927
CompletionString, ModuleName, BriefDocComment, AssociatedUSRs,
825-
NotRecommended, DiagnosticSeverity, DiagnosticMessage) {
928+
ResultType, NotRecommended, DiagnosticSeverity, DiagnosticMessage) {
826929
assert(AssociatedDecl && "should have a decl");
827930
}
828931

@@ -856,6 +959,8 @@ class ContextFreeCodeCompletionResult {
856959

857960
ArrayRef<StringRef> getAssociatedUSRs() const { return AssociatedUSRs; }
858961

962+
CodeCompletionResultType *getResultType() const { return ResultType; }
963+
859964
ContextFreeNotRecommendedReason getNotRecommendedReason() const {
860965
return NotRecommended;
861966
}
@@ -886,6 +991,40 @@ class ContextFreeCodeCompletionResult {
886991
static bool getDeclIsSystem(const Decl *D);
887992
};
888993

994+
/// The expected contextual type(s) for code-completion.
995+
struct ExpectedTypeContext {
996+
/// Possible types of the code completion expression.
997+
llvm::SmallVector<Type, 4> possibleTypes;
998+
999+
/// Pre typechecked type of the expression at the completion position.
1000+
Type idealType;
1001+
1002+
/// Whether the `ExpectedTypes` comes from a single-expression body, e.g.
1003+
/// `foo({ here })`.
1004+
///
1005+
/// Since the input may be incomplete, we take into account that the types are
1006+
/// only a hint.
1007+
bool isImplicitSingleExpressionReturn = false;
1008+
bool preferNonVoid = false;
1009+
1010+
bool empty() const { return possibleTypes.empty(); }
1011+
bool requiresNonVoid() const {
1012+
if (isImplicitSingleExpressionReturn)
1013+
return false;
1014+
if (preferNonVoid)
1015+
return true;
1016+
if (possibleTypes.empty())
1017+
return false;
1018+
return std::all_of(possibleTypes.begin(), possibleTypes.end(),
1019+
[](Type Ty) { return !Ty->isVoid(); });
1020+
}
1021+
1022+
ExpectedTypeContext() = default;
1023+
ExpectedTypeContext(ArrayRef<Type> types, bool isImplicitSingleExprReturn)
1024+
: possibleTypes(types.begin(), types.end()),
1025+
isImplicitSingleExpressionReturn(isImplicitSingleExprReturn) {}
1026+
};
1027+
8891028
/// A single code completion result enriched with information that depend on
8901029
/// the completion's usage context.
8911030
class CodeCompletionResult {
@@ -945,8 +1084,7 @@ class CodeCompletionResult {
9451084
static_assert(int(ExpectedTypeRelation::MAX_VALUE) < 1 << 3, "");
9461085

9471086
public:
948-
/// Enrich a \c ContextFreeCodeCompletionResult with the following contextual
949-
/// information.
1087+
/// Memberwise initializer
9501088
CodeCompletionResult(ContextFreeCodeCompletionResult ContextFree,
9511089
SemanticContextKind SemanticContext,
9521090
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
@@ -960,6 +1098,19 @@ class CodeCompletionResult {
9601098
DiagnosticMessage(DiagnosticMessage), NumBytesToErase(NumBytesToErase),
9611099
TypeDistance(TypeDistance) {}
9621100

1101+
/// Enrich a \c ContextFreeCodeCompletionResult with the following contextual
1102+
/// information.
1103+
/// This computes the type relation between the completion item and its
1104+
/// expected type context.
1105+
CodeCompletionResult(ContextFreeCodeCompletionResult ContextFree,
1106+
SemanticContextKind SemanticContext,
1107+
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
1108+
const ExpectedTypeContext &TypeContext,
1109+
const DeclContext *DC,
1110+
ContextualNotRecommendedReason NotRecommended,
1111+
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
1112+
StringRef DiagnosticMessage);
1113+
9631114
const ContextFreeCodeCompletionResult &getContextFreeResult() const {
9641115
return ContextFree;
9651116
}

0 commit comments

Comments
 (0)