Skip to content

Commit 6dd5d94

Browse files
committed
[CodeCompletion] Introduce "Flair" in code completion
To describe fine grained priorities. Introduce 'CodeCompletionFlair' that is a set of more descriptive flags for prioritizing completion items. This aims to replace ' SemanticContextKind::ExpressionSpecific' which was a "catch all" prioritization flag.
1 parent 509c498 commit 6dd5d94

36 files changed

+381
-307
lines changed

include/swift/IDE/CodeCompletion.h

+26-32
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Identifier.h"
1717
#include "swift/Basic/Debug.h"
1818
#include "swift/Basic/LLVM.h"
19+
#include "swift/Basic/OptionSet.h"
1920
#include "llvm/ADT/ArrayRef.h"
2021
#include "llvm/ADT/StringMap.h"
2122
#include "llvm/ADT/StringRef.h"
@@ -375,33 +376,6 @@ enum class SemanticContextKind {
375376
/// Used in cases when the concept of semantic context is not applicable.
376377
None,
377378

378-
/// This is a highly-likely expression-context-specific completion
379-
/// result. This description is intentionally vague: this is a catch-all
380-
/// category for all heuristics for highly-likely results.
381-
///
382-
/// For example, the name of an overridden superclass member inside a nominal
383-
/// member function has ExpressionSpecific context:
384-
/// \code
385-
/// class Base {
386-
/// init() {}
387-
/// init(a: Int) {}
388-
/// func foo() {}
389-
/// func bar() {}
390-
/// }
391-
/// class Derived {
392-
/// init() {
393-
/// super. // init() -- ExpressionSpecific
394-
/// // init(a: Int) -- Super
395-
/// }
396-
///
397-
/// func foo() {
398-
/// super. // foo() -- ExpressionSpecific
399-
/// // bar() -- Super
400-
/// }
401-
/// }
402-
/// \endcode
403-
ExpressionSpecific,
404-
405379
/// A declaration from the same function.
406380
Local,
407381

@@ -434,6 +408,16 @@ enum class SemanticContextKind {
434408
OtherModule,
435409
};
436410

411+
enum class CodeCompletionFlairBit: uint8_t {
412+
/// **Deprecated**. Old style catch-all prioritization.
413+
ExpressionSpecific = 1 << 0,
414+
415+
/// E.g. override func foo() { super.foo() ...
416+
SuperChain = 1 << 1,
417+
};
418+
419+
using CodeCompletionFlair = OptionSet<CodeCompletionFlairBit>;
420+
437421
/// The declaration kind of a code completion result, if it is a declaration.
438422
enum class CodeCompletionDeclKind {
439423
Module,
@@ -615,6 +599,7 @@ class CodeCompletionResult {
615599
unsigned AssociatedKind : 8;
616600
unsigned KnownOperatorKind : 6;
617601
unsigned SemanticContext : 3;
602+
unsigned Flair: 8;
618603
unsigned IsArgumentLabels : 1;
619604
unsigned NotRecommended : 4;
620605
unsigned IsSystem : 1;
@@ -640,14 +625,15 @@ class CodeCompletionResult {
640625
///
641626
/// \note The caller must ensure \c CodeCompletionString outlives this result.
642627
CodeCompletionResult(ResultKind Kind, SemanticContextKind SemanticContext,
628+
CodeCompletionFlair Flair,
643629
bool IsArgumentLabels, unsigned NumBytesToErase,
644630
CodeCompletionString *CompletionString,
645631
ExpectedTypeRelation TypeDistance,
646632
CodeCompletionOperatorKind KnownOperatorKind =
647633
CodeCompletionOperatorKind::None,
648634
StringRef BriefDocComment = StringRef())
649635
: Kind(Kind), KnownOperatorKind(unsigned(KnownOperatorKind)),
650-
SemanticContext(unsigned(SemanticContext)),
636+
SemanticContext(unsigned(SemanticContext)), Flair(unsigned(Flair.toRaw())),
651637
IsArgumentLabels(unsigned(IsArgumentLabels)),
652638
NotRecommended(unsigned(NotRecommendedReason::None)),
653639
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
@@ -668,12 +654,13 @@ class CodeCompletionResult {
668654
/// \note The caller must ensure \c CodeCompletionString outlives this result.
669655
CodeCompletionResult(CodeCompletionKeywordKind Kind,
670656
SemanticContextKind SemanticContext,
657+
CodeCompletionFlair Flair,
671658
bool IsArgumentLabels, unsigned NumBytesToErase,
672659
CodeCompletionString *CompletionString,
673660
ExpectedTypeRelation TypeDistance,
674661
StringRef BriefDocComment = StringRef())
675662
: Kind(Keyword), KnownOperatorKind(0),
676-
SemanticContext(unsigned(SemanticContext)),
663+
SemanticContext(unsigned(SemanticContext)), Flair(unsigned(Flair.toRaw())),
677664
IsArgumentLabels(unsigned(IsArgumentLabels)),
678665
NotRecommended(unsigned(NotRecommendedReason::None)),
679666
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
@@ -688,11 +675,12 @@ class CodeCompletionResult {
688675
/// \note The caller must ensure \c CodeCompletionString outlives this result.
689676
CodeCompletionResult(CodeCompletionLiteralKind LiteralKind,
690677
SemanticContextKind SemanticContext,
678+
CodeCompletionFlair Flair,
691679
bool IsArgumentLabels, unsigned NumBytesToErase,
692680
CodeCompletionString *CompletionString,
693681
ExpectedTypeRelation TypeDistance)
694682
: Kind(Literal), KnownOperatorKind(0),
695-
SemanticContext(unsigned(SemanticContext)),
683+
SemanticContext(unsigned(SemanticContext)), Flair(unsigned(Flair.toRaw())),
696684
IsArgumentLabels(unsigned(IsArgumentLabels)),
697685
NotRecommended(unsigned(NotRecommendedReason::None)),
698686
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
@@ -708,6 +696,7 @@ class CodeCompletionResult {
708696
/// arguments outlive this result, typically by storing them in the same
709697
/// \c CodeCompletionResultSink as the result itself.
710698
CodeCompletionResult(SemanticContextKind SemanticContext,
699+
CodeCompletionFlair Flair,
711700
bool IsArgumentLabels, unsigned NumBytesToErase,
712701
CodeCompletionString *CompletionString,
713702
const Decl *AssociatedDecl, StringRef ModuleName,
@@ -717,7 +706,7 @@ class CodeCompletionResult {
717706
ArrayRef<std::pair<StringRef, StringRef>> DocWords,
718707
enum ExpectedTypeRelation TypeDistance)
719708
: Kind(ResultKind::Declaration), KnownOperatorKind(0),
720-
SemanticContext(unsigned(SemanticContext)),
709+
SemanticContext(unsigned(SemanticContext)), Flair(unsigned(Flair.toRaw())),
721710
IsArgumentLabels(unsigned(IsArgumentLabels)),
722711
NotRecommended(unsigned(NotRecReason)),
723712
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
@@ -737,6 +726,7 @@ class CodeCompletionResult {
737726

738727
// Used by deserialization.
739728
CodeCompletionResult(SemanticContextKind SemanticContext,
729+
CodeCompletionFlair Flair,
740730
bool IsArgumentLabels, unsigned NumBytesToErase,
741731
CodeCompletionString *CompletionString,
742732
CodeCompletionDeclKind DeclKind, bool IsSystem,
@@ -749,7 +739,7 @@ class CodeCompletionResult {
749739
CodeCompletionOperatorKind KnownOperatorKind)
750740
: Kind(ResultKind::Declaration),
751741
KnownOperatorKind(unsigned(KnownOperatorKind)),
752-
SemanticContext(unsigned(SemanticContext)),
742+
SemanticContext(unsigned(SemanticContext)), Flair(unsigned(Flair.toRaw())),
753743
IsArgumentLabels(unsigned(IsArgumentLabels)),
754744
NotRecommended(unsigned(NotRecReason)), IsSystem(IsSystem),
755745
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
@@ -813,6 +803,10 @@ class CodeCompletionResult {
813803
return static_cast<SemanticContextKind>(SemanticContext);
814804
}
815805

806+
CodeCompletionFlair getFlair() const {
807+
return static_cast<CodeCompletionFlair>(Flair);
808+
}
809+
816810
bool isArgumentLabels() const {
817811
return static_cast<bool>(IsArgumentLabels);
818812
}

lib/IDE/CodeCompletion.cpp

+51-19
Original file line numberDiff line numberDiff line change
@@ -708,9 +708,6 @@ void CodeCompletionResult::printPrefix(raw_ostream &OS) const {
708708
case SemanticContextKind::None:
709709
Prefix.append("None");
710710
break;
711-
case SemanticContextKind::ExpressionSpecific:
712-
Prefix.append("ExprSpecific");
713-
break;
714711
case SemanticContextKind::Local:
715712
Prefix.append("Local");
716713
break;
@@ -732,6 +729,19 @@ void CodeCompletionResult::printPrefix(raw_ostream &OS) const {
732729
Prefix.append((Twine("[") + ModuleName + "]").str());
733730
break;
734731
}
732+
if (getFlair().toRaw()) {
733+
Prefix.append("/Flair[");
734+
bool isFirstFlair = true;
735+
#define PRINT_FLAIR(KIND, NAME) \
736+
if (getFlair().contains(CodeCompletionFlairBit::KIND)) { \
737+
if (isFirstFlair) { isFirstFlair = false; } \
738+
else { Prefix.append(","); } \
739+
Prefix.append(NAME); \
740+
}
741+
PRINT_FLAIR(ExpressionSpecific, "ExprSpecific");
742+
PRINT_FLAIR(SuperChain, "SuperChain");
743+
Prefix.append("]");
744+
}
735745
if (NotRecommended)
736746
Prefix.append("/NotRecommended");
737747
if (IsSystem)
@@ -1294,7 +1304,7 @@ CodeCompletionResult *CodeCompletionResultBuilder::takeResult() {
12941304
}
12951305

12961306
return new (*Sink.Allocator) CodeCompletionResult(
1297-
SemanticContext, IsArgumentLabels, NumBytesToErase, CCS, AssociatedDecl,
1307+
SemanticContext, Flair, IsArgumentLabels, NumBytesToErase, CCS, AssociatedDecl,
12981308
ModuleName, NotRecReason, copyString(*Sink.Allocator, BriefComment),
12991309
copyAssociatedUSRs(*Sink.Allocator, AssociatedDecl),
13001310
copyArray(*Sink.Allocator, CommentWords), ExpectedTypeRelation);
@@ -1303,21 +1313,21 @@ CodeCompletionResult *CodeCompletionResultBuilder::takeResult() {
13031313
case CodeCompletionResult::ResultKind::Keyword:
13041314
return new (*Sink.Allocator)
13051315
CodeCompletionResult(
1306-
KeywordKind, SemanticContext, IsArgumentLabels, NumBytesToErase,
1316+
KeywordKind, SemanticContext, Flair, IsArgumentLabels, NumBytesToErase,
13071317
CCS, ExpectedTypeRelation,
13081318
copyString(*Sink.Allocator, BriefDocComment));
13091319

13101320
case CodeCompletionResult::ResultKind::BuiltinOperator:
13111321
case CodeCompletionResult::ResultKind::Pattern:
13121322
return new (*Sink.Allocator) CodeCompletionResult(
1313-
Kind, SemanticContext, IsArgumentLabels, NumBytesToErase, CCS,
1323+
Kind, SemanticContext, Flair, IsArgumentLabels, NumBytesToErase, CCS,
13141324
ExpectedTypeRelation, CodeCompletionOperatorKind::None,
13151325
copyString(*Sink.Allocator, BriefDocComment));
13161326

13171327
case CodeCompletionResult::ResultKind::Literal:
13181328
assert(LiteralKind.hasValue());
13191329
return new (*Sink.Allocator)
1320-
CodeCompletionResult(*LiteralKind, SemanticContext, IsArgumentLabels,
1330+
CodeCompletionResult(*LiteralKind, SemanticContext, Flair, IsArgumentLabels,
13211331
NumBytesToErase, CCS, ExpectedTypeRelation);
13221332
}
13231333

@@ -2180,9 +2190,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
21802190
return SemanticContextKind::Local;
21812191

21822192
case DeclVisibilityKind::MemberOfCurrentNominal:
2183-
if (IsSuperRefExpr &&
2184-
CurrentMethod && CurrentMethod->getOverriddenDecl() == D)
2185-
return SemanticContextKind::ExpressionSpecific;
21862193
return SemanticContextKind::CurrentNominal;
21872194

21882195
case DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal:
@@ -2644,7 +2651,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26442651
Builder.addAnnotatedAsync();
26452652

26462653
if (isUnresolvedMemberIdealType(VarType))
2647-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
2654+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
26482655
}
26492656

26502657
static bool hasInterestingDefaultValues(const AbstractFunctionDecl *func) {
@@ -2782,7 +2789,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27822789
if (ParentKind != StmtKind::If && ParentKind != StmtKind::Guard)
27832790
return;
27842791
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword,
2785-
SemanticContextKind::ExpressionSpecific, expectedTypeContext);
2792+
// FIXME: SemanticContextKind::Local is not correct.
2793+
// Use 'None' (and fix prioritization) or introduce a new context.
2794+
SemanticContextKind::Local, expectedTypeContext);
2795+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
27862796
Builder.addBaseName("available");
27872797
Builder.addLeftParen();
27882798
Builder.addSimpleTypedParameter("Platform", /*IsVarArg=*/true);
@@ -3072,6 +3082,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
30723082
setClangDeclKeywords(FD, Pairs, Builder);
30733083
Builder.setAssociatedDecl(FD);
30743084

3085+
if (IsSuperRefExpr && CurrentMethod &&
3086+
CurrentMethod->getOverriddenDecl() == FD)
3087+
Builder.addFlair(CodeCompletionFlairBit::SuperChain);
3088+
30753089
if (NotRecommended)
30763090
Builder.setNotRecommended(*NotRecommended);
30773091

@@ -3161,7 +3175,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
31613175
ResultType, expectedTypeContext, CurrDeclContext));
31623176

31633177
if (isUnresolvedMemberIdealType(ResultType))
3164-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
3178+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
31653179

31663180
if (!IsImplicitlyCurriedInstanceMethod &&
31673181
expectedTypeContext.requiresNonVoid() &&
@@ -3215,6 +3229,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32153229
expectedTypeContext);
32163230
setClangDeclKeywords(CD, Pairs, Builder);
32173231
Builder.setAssociatedDecl(CD);
3232+
3233+
if (IsSuperRefExpr && CurrentMethod &&
3234+
CurrentMethod->getOverriddenDecl() == CD)
3235+
Builder.addFlair(CodeCompletionFlairBit::SuperChain);
3236+
32183237
if (needInit) {
32193238
assert(addName.empty());
32203239
addLeadingDot(Builder);
@@ -3458,11 +3477,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34583477
CommandWordsPairs Pairs;
34593478
CodeCompletionResultBuilder Builder(
34603479
Sink, CodeCompletionResult::ResultKind::Declaration,
3461-
HasTypeContext ? SemanticContextKind::ExpressionSpecific
3462-
: getSemanticContext(EED, Reason, dynamicLookupInfo),
3480+
getSemanticContext(EED, Reason, dynamicLookupInfo),
34633481
expectedTypeContext);
34643482
Builder.setAssociatedDecl(EED);
34653483
setClangDeclKeywords(EED, Pairs, Builder);
3484+
if (HasTypeContext)
3485+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
3486+
34663487
addLeadingDot(Builder);
34673488
addValueBaseName(Builder, EED->getBaseIdentifier());
34683489

@@ -3486,7 +3507,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34863507
addTypeAnnotation(Builder, EnumType, EED->getGenericSignatureOfContext());
34873508

34883509
if (isUnresolvedMemberIdealType(EnumType))
3489-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
3510+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
34903511
}
34913512

34923513
void addKeyword(StringRef Name, Type TypeAnnotation = Type(),
@@ -4579,13 +4600,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
45794600
continue;
45804601
CodeCompletionResultBuilder Builder(
45814602
Sink, CodeCompletionResult::ResultKind::Pattern,
4582-
SemanticContextKind::ExpressionSpecific, {});
4603+
// FIXME: SemanticContextKind::Local is not correct.
4604+
// Use 'None' (and fix prioritization) or introduce a new context.
4605+
SemanticContextKind::Local, {});
45834606
Builder.addCallParameter(Arg->getLabel(), Identifier(),
45844607
Arg->getPlainType(), ContextType,
45854608
Arg->isVariadic(), Arg->isInOut(),
45864609
/*isIUO=*/false, Arg->isAutoClosure(),
45874610
/*useUnderscoreLabel=*/true,
45884611
isLabeledTrailingClosure);
4612+
Builder.setIsArgumentLabels();
4613+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
45894614
auto Ty = Arg->getPlainType();
45904615
if (Arg->isInOut()) {
45914616
Ty = InOutType::get(Ty);
@@ -6202,12 +6227,16 @@ static void addPlatformConditions(CodeCompletionResultSink &Sink) {
62026227
consumer) {
62036228
CodeCompletionResultBuilder Builder(
62046229
Sink, CodeCompletionResult::ResultKind::Pattern,
6205-
SemanticContextKind::ExpressionSpecific, {});
6230+
// FIXME: SemanticContextKind::CurrentModule is not correct.
6231+
// Use 'None' (and fix prioritization) or introduce a new context.
6232+
SemanticContextKind::CurrentModule, {});
6233+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
62066234
Builder.addBaseName(Name);
62076235
Builder.addLeftParen();
62086236
consumer(Builder);
62096237
Builder.addRightParen();
62106238
};
6239+
62116240
addWithName("os", [](CodeCompletionResultBuilder &Builder) {
62126241
Builder.addSimpleNamedParameter("name");
62136242
});
@@ -6248,7 +6277,10 @@ static void addConditionalCompilationFlags(ASTContext &Ctx,
62486277
// TODO: Should we filter out some flags?
62496278
CodeCompletionResultBuilder Builder(
62506279
Sink, CodeCompletionResult::ResultKind::Keyword,
6251-
SemanticContextKind::ExpressionSpecific, {});
6280+
// FIXME: SemanticContextKind::CurrentModule is not correct.
6281+
// Use 'None' (and fix prioritization) or introduce a new context.
6282+
SemanticContextKind::CurrentModule, {});
6283+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
62526284
Builder.addTextChunk(Flag);
62536285
}
62546286
}

lib/IDE/CodeCompletionCache.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,18 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
226226
}
227227

228228
CodeCompletionResult *result = nullptr;
229+
CodeCompletionFlair Flair;
229230
if (kind == CodeCompletionResult::Declaration) {
230231
result = new (*V.Sink.Allocator) CodeCompletionResult(
231-
context, /*IsArgumentLabels=*/false, numBytesToErase, string,
232+
context, Flair, /*IsArgumentLabels=*/false, numBytesToErase, string,
232233
declKind, isSystem, moduleName, notRecommended, briefDocComment,
233234
copyArray(*V.Sink.Allocator, ArrayRef<StringRef>(assocUSRs)),
234235
copyArray(*V.Sink.Allocator,
235236
ArrayRef<std::pair<StringRef, StringRef>>(declKeywords)),
236237
CodeCompletionResult::Unknown, opKind);
237238
} else {
238239
result = new (*V.Sink.Allocator)
239-
CodeCompletionResult(kind, context, /*IsArgumentLabels=*/false,
240+
CodeCompletionResult(kind, context, Flair, /*IsArgumentLabels=*/false,
240241
numBytesToErase, string,
241242
CodeCompletionResult::NotApplicable, opKind);
242243
}

lib/IDE/CodeCompletionResultBuilder.h

+5
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class CodeCompletionResultBuilder {
7676
CodeCompletionResultSink &Sink;
7777
CodeCompletionResult::ResultKind Kind;
7878
SemanticContextKind SemanticContext;
79+
CodeCompletionFlair Flair;
7980
unsigned NumBytesToErase = 0;
8081
const Decl *AssociatedDecl = nullptr;
8182
Optional<CodeCompletionLiteralKind> LiteralKind;
@@ -155,6 +156,10 @@ class CodeCompletionResultBuilder {
155156
SemanticContext = Kind;
156157
}
157158

159+
void addFlair(CodeCompletionFlair Options) {
160+
Flair |= Options;
161+
}
162+
158163
void setIsArgumentLabels(bool Flag = true) {
159164
IsArgumentLabels = Flag;
160165
}

0 commit comments

Comments
 (0)