Skip to content

Commit c20f102

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. (cherry picked from commit 6dd5d94)
1 parent f780977 commit c20f102

36 files changed

+381
-307
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 26 additions & 32 deletions
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

Lines changed: 51 additions & 19 deletions
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:
@@ -2639,7 +2646,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26392646
Builder.addAnnotatedAsync();
26402647

26412648
if (isUnresolvedMemberIdealType(VarType))
2642-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
2649+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
26432650
}
26442651

26452652
static bool hasInterestingDefaultValues(const AbstractFunctionDecl *func) {
@@ -2777,7 +2784,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27772784
if (ParentKind != StmtKind::If && ParentKind != StmtKind::Guard)
27782785
return;
27792786
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword,
2780-
SemanticContextKind::ExpressionSpecific, expectedTypeContext);
2787+
// FIXME: SemanticContextKind::Local is not correct.
2788+
// Use 'None' (and fix prioritization) or introduce a new context.
2789+
SemanticContextKind::Local, expectedTypeContext);
2790+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
27812791
Builder.addBaseName("available");
27822792
Builder.addLeftParen();
27832793
Builder.addSimpleTypedParameter("Platform", /*IsVarArg=*/true);
@@ -3067,6 +3077,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
30673077
setClangDeclKeywords(FD, Pairs, Builder);
30683078
Builder.setAssociatedDecl(FD);
30693079

3080+
if (IsSuperRefExpr && CurrentMethod &&
3081+
CurrentMethod->getOverriddenDecl() == FD)
3082+
Builder.addFlair(CodeCompletionFlairBit::SuperChain);
3083+
30703084
if (NotRecommended)
30713085
Builder.setNotRecommended(*NotRecommended);
30723086

@@ -3156,7 +3170,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
31563170
ResultType, expectedTypeContext, CurrDeclContext));
31573171

31583172
if (isUnresolvedMemberIdealType(ResultType))
3159-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
3173+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
31603174

31613175
if (!IsImplicitlyCurriedInstanceMethod &&
31623176
expectedTypeContext.requiresNonVoid() &&
@@ -3210,6 +3224,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32103224
expectedTypeContext);
32113225
setClangDeclKeywords(CD, Pairs, Builder);
32123226
Builder.setAssociatedDecl(CD);
3227+
3228+
if (IsSuperRefExpr && CurrentMethod &&
3229+
CurrentMethod->getOverriddenDecl() == CD)
3230+
Builder.addFlair(CodeCompletionFlairBit::SuperChain);
3231+
32133232
if (needInit) {
32143233
assert(addName.empty());
32153234
addLeadingDot(Builder);
@@ -3453,11 +3472,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34533472
CommandWordsPairs Pairs;
34543473
CodeCompletionResultBuilder Builder(
34553474
Sink, CodeCompletionResult::ResultKind::Declaration,
3456-
HasTypeContext ? SemanticContextKind::ExpressionSpecific
3457-
: getSemanticContext(EED, Reason, dynamicLookupInfo),
3475+
getSemanticContext(EED, Reason, dynamicLookupInfo),
34583476
expectedTypeContext);
34593477
Builder.setAssociatedDecl(EED);
34603478
setClangDeclKeywords(EED, Pairs, Builder);
3479+
if (HasTypeContext)
3480+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
3481+
34613482
addLeadingDot(Builder);
34623483
addValueBaseName(Builder, EED->getBaseIdentifier());
34633484

@@ -3481,7 +3502,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34813502
addTypeAnnotation(Builder, EnumType, EED->getGenericSignatureOfContext());
34823503

34833504
if (isUnresolvedMemberIdealType(EnumType))
3484-
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
3505+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
34853506
}
34863507

34873508
void addKeyword(StringRef Name, Type TypeAnnotation = Type(),
@@ -4574,13 +4595,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
45744595
continue;
45754596
CodeCompletionResultBuilder Builder(
45764597
Sink, CodeCompletionResult::ResultKind::Pattern,
4577-
SemanticContextKind::ExpressionSpecific, {});
4598+
// FIXME: SemanticContextKind::Local is not correct.
4599+
// Use 'None' (and fix prioritization) or introduce a new context.
4600+
SemanticContextKind::Local, {});
45784601
Builder.addCallParameter(Arg->getLabel(), Identifier(),
45794602
Arg->getPlainType(), ContextType,
45804603
Arg->isVariadic(), Arg->isInOut(),
45814604
/*isIUO=*/false, Arg->isAutoClosure(),
45824605
/*useUnderscoreLabel=*/true,
45834606
isLabeledTrailingClosure);
4607+
Builder.setIsArgumentLabels();
4608+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
45844609
auto Ty = Arg->getPlainType();
45854610
if (Arg->isInOut()) {
45864611
Ty = InOutType::get(Ty);
@@ -6184,12 +6209,16 @@ static void addPlatformConditions(CodeCompletionResultSink &Sink) {
61846209
consumer) {
61856210
CodeCompletionResultBuilder Builder(
61866211
Sink, CodeCompletionResult::ResultKind::Pattern,
6187-
SemanticContextKind::ExpressionSpecific, {});
6212+
// FIXME: SemanticContextKind::CurrentModule is not correct.
6213+
// Use 'None' (and fix prioritization) or introduce a new context.
6214+
SemanticContextKind::CurrentModule, {});
6215+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
61886216
Builder.addBaseName(Name);
61896217
Builder.addLeftParen();
61906218
consumer(Builder);
61916219
Builder.addRightParen();
61926220
};
6221+
61936222
addWithName("os", [](CodeCompletionResultBuilder &Builder) {
61946223
Builder.addSimpleNamedParameter("name");
61956224
});
@@ -6230,7 +6259,10 @@ static void addConditionalCompilationFlags(ASTContext &Ctx,
62306259
// TODO: Should we filter out some flags?
62316260
CodeCompletionResultBuilder Builder(
62326261
Sink, CodeCompletionResult::ResultKind::Keyword,
6233-
SemanticContextKind::ExpressionSpecific, {});
6262+
// FIXME: SemanticContextKind::CurrentModule is not correct.
6263+
// Use 'None' (and fix prioritization) or introduce a new context.
6264+
SemanticContextKind::CurrentModule, {});
6265+
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
62346266
Builder.addTextChunk(Flag);
62356267
}
62366268
}

lib/IDE/CodeCompletionCache.cpp

Lines changed: 3 additions & 2 deletions
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

Lines changed: 5 additions & 0 deletions
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)