@@ -741,6 +741,8 @@ void CodeCompletionResult::printPrefix(raw_ostream &OS) const {
741741 PRINT_FLAIR (ExpressionSpecific, " ExprSpecific" );
742742 PRINT_FLAIR (SuperChain, " SuperChain" );
743743 PRINT_FLAIR (ArgumentLabels, " ArgLabels" );
744+ PRINT_FLAIR (CommonKeywordAtCurrentPosition, " CommonKeyword" )
745+ PRINT_FLAIR (RareKeywordAtCurrentPosition, " RareKeyword" )
744746 Prefix.append (" ]" );
745747 }
746748 if (NotRecommended)
@@ -1540,6 +1542,12 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
15401542 CodeCompletionResult::ResultKind::Keyword,
15411543 SemanticContextKind::CurrentNominal,
15421544 {});
1545+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(CurDeclContext)) {
1546+ if (AFD->getOverriddenDecl () != nullptr ) {
1547+ Builder.addFlair (CodeCompletionFlairBit::CommonKeywordAtCurrentPosition);
1548+ }
1549+ }
1550+
15431551 Builder.setKeywordKind (CodeCompletionKeywordKind::kw_super);
15441552 Builder.addKeyword (" super" );
15451553 Builder.addTypeAnnotation (ST, PrintOptions ());
@@ -1822,6 +1830,71 @@ static bool canDeclContextHandleAsync(const DeclContext *DC) {
18221830 return false ;
18231831}
18241832
1833+ // / Returns \c true only if the completion is happening for top-level
1834+ // / declrarations. i.e.:
1835+ // /
1836+ // / if condition {
1837+ // / #false#
1838+ // / }
1839+ // / expr.#false#
1840+ // /
1841+ // / #true#
1842+ // /
1843+ // / struct S {
1844+ // / #false#
1845+ // / func foo() {
1846+ // / #false#
1847+ // / }
1848+ // / }
1849+ static bool isCodeCompletionAtTopLevel (DeclContext *DC) {
1850+ if (DC->isModuleScopeContext ())
1851+ return true ;
1852+
1853+ // CC token at top-level is parsed as an expression. If the only element
1854+ // body of the TopLevelCodeDecl is a CodeCompletionExpr without a base
1855+ // expression, the user might be writing a top-level declaration.
1856+ if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(DC)) {
1857+ auto body = TLCD->getBody ();
1858+ if (!body || body->empty ())
1859+ return true ;
1860+ if (body->getElements ().size () > 1 )
1861+ return false ;
1862+ auto expr = body->getFirstElement ().dyn_cast <Expr *>();
1863+ if (!expr)
1864+ return false ;
1865+ if (CodeCompletionExpr *CCExpr = dyn_cast<CodeCompletionExpr>(expr)) {
1866+ if (CCExpr->getBase () == nullptr )
1867+ return true ;
1868+ }
1869+ }
1870+
1871+ return false ;
1872+ }
1873+
1874+ // / Returns \c true if the completion is happening in local context such as
1875+ // / inside function bodies. i.e.:
1876+ // /
1877+ // / if condition {
1878+ // / #true#
1879+ // / }
1880+ // / expr.#true#
1881+ // /
1882+ // / #false#
1883+ // /
1884+ // / struct S {
1885+ // / #false#
1886+ // / func foo() {
1887+ // / #true#
1888+ // / }
1889+ // / }
1890+ static bool isCompletionDeclContextLocalContext (DeclContext *DC) {
1891+ if (!DC->isLocalContext ())
1892+ return false ;
1893+ if (isCodeCompletionAtTopLevel (DC))
1894+ return false ;
1895+ return true ;
1896+ }
1897+
18251898// / Build completions by doing visible decl lookup from a context.
18261899class CompletionLookup final : public swift::VisibleDeclConsumer {
18271900 CodeCompletionResultSink &Sink;
@@ -5925,22 +5998,127 @@ static void
59255998addKeyword (CodeCompletionResultSink &Sink, StringRef Name,
59265999 CodeCompletionKeywordKind Kind, StringRef TypeAnnotation = " " ,
59276000 CodeCompletionResult::ExpectedTypeRelation TypeRelation =
5928- CodeCompletionResult::ExpectedTypeRelation::NotApplicable) {
6001+ CodeCompletionResult::ExpectedTypeRelation::NotApplicable,
6002+ CodeCompletionFlair Flair = {}) {
59296003 CodeCompletionResultBuilder Builder (Sink,
59306004 CodeCompletionResult::ResultKind::Keyword,
59316005 SemanticContextKind::None, {});
59326006 Builder.setKeywordKind (Kind);
59336007 Builder.addKeyword (Name);
6008+ Builder.addFlair (Flair);
59346009 if (!TypeAnnotation.empty ())
59356010 Builder.addTypeAnnotation (TypeAnnotation);
59366011 Builder.setExpectedTypeRelation (TypeRelation);
59376012}
59386013
5939- static void addDeclKeywords (CodeCompletionResultSink &Sink,
6014+ static void addDeclKeywords (CodeCompletionResultSink &Sink, DeclContext *DC,
59406015 bool IsConcurrencyEnabled,
59416016 bool IsDistributedEnabled) {
6017+ auto isTypeDeclIntroducer = [](CodeCompletionKeywordKind Kind,
6018+ Optional<DeclAttrKind> DAK) -> bool {
6019+ switch (Kind) {
6020+ case CodeCompletionKeywordKind::kw_protocol:
6021+ case CodeCompletionKeywordKind::kw_class:
6022+ case CodeCompletionKeywordKind::kw_struct:
6023+ case CodeCompletionKeywordKind::kw_enum:
6024+ case CodeCompletionKeywordKind::kw_extension:
6025+ return true ;
6026+ case CodeCompletionKeywordKind::None:
6027+ if (DAK && *DAK == DeclAttrKind::DAK_Actor) {
6028+ return true ;
6029+ }
6030+ break ;
6031+ default :
6032+ break ;
6033+ }
6034+ return false ;
6035+ };
6036+ auto isTopLevelOnlyDeclIntroducer = [](CodeCompletionKeywordKind Kind,
6037+ Optional<DeclAttrKind> DAK) -> bool {
6038+ switch (Kind) {
6039+ case CodeCompletionKeywordKind::kw_operator:
6040+ case CodeCompletionKeywordKind::kw_precedencegroup:
6041+ case CodeCompletionKeywordKind::kw_import:
6042+ case CodeCompletionKeywordKind::kw_protocol:
6043+ case CodeCompletionKeywordKind::kw_extension:
6044+ return true ;
6045+ default :
6046+ return false ;
6047+ }
6048+ };
6049+
6050+ auto getFlair = [&](CodeCompletionKeywordKind Kind,
6051+ Optional<DeclAttrKind> DAK) -> CodeCompletionFlair {
6052+ if (isCodeCompletionAtTopLevel (DC) &&
6053+ !DC->getParentSourceFile ()->isScriptMode ()) {
6054+ // Type decls are common in library file top-level.
6055+ if (isTypeDeclIntroducer (Kind, DAK))
6056+ return CodeCompletionFlairBit::CommonKeywordAtCurrentPosition;
6057+ }
6058+ if (isa<ProtocolDecl>(DC)) {
6059+ // Protocols cannot have nested type decls (other than 'typealias').
6060+ if (isTypeDeclIntroducer (Kind, DAK))
6061+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6062+ }
6063+ if (DC->isTypeContext ()) {
6064+ // Top-level only decls are invalid in type context.
6065+ if (isTopLevelOnlyDeclIntroducer (Kind, DAK))
6066+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6067+ }
6068+ if (isCompletionDeclContextLocalContext (DC)) {
6069+ // Local type decl are valid, but not common.
6070+ if (isTypeDeclIntroducer (Kind, DAK))
6071+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6072+
6073+ // Top-level only decls are invalid in function body.
6074+ if (isTopLevelOnlyDeclIntroducer (Kind, DAK))
6075+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6076+
6077+ // 'init', 'deinit' and 'subscript' are invalid in function body.
6078+ // Access control modifiers are invalid in function body.
6079+ switch (Kind) {
6080+ case CodeCompletionKeywordKind::kw_init:
6081+ case CodeCompletionKeywordKind::kw_deinit:
6082+ case CodeCompletionKeywordKind::kw_subscript:
6083+ case CodeCompletionKeywordKind::kw_private:
6084+ case CodeCompletionKeywordKind::kw_fileprivate:
6085+ case CodeCompletionKeywordKind::kw_internal:
6086+ case CodeCompletionKeywordKind::kw_public:
6087+ case CodeCompletionKeywordKind::kw_static:
6088+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6089+
6090+ default :
6091+ break ;
6092+ }
6093+
6094+ // These modifiers are invalid for decls in function body.
6095+ if (DAK) {
6096+ switch (*DAK) {
6097+ case DeclAttrKind::DAK_Lazy:
6098+ case DeclAttrKind::DAK_Final:
6099+ case DeclAttrKind::DAK_Infix:
6100+ case DeclAttrKind::DAK_Frozen:
6101+ case DeclAttrKind::DAK_Prefix:
6102+ case DeclAttrKind::DAK_Postfix:
6103+ case DeclAttrKind::DAK_Dynamic:
6104+ case DeclAttrKind::DAK_Override:
6105+ case DeclAttrKind::DAK_Optional:
6106+ case DeclAttrKind::DAK_Required:
6107+ case DeclAttrKind::DAK_Convenience:
6108+ case DeclAttrKind::DAK_AccessControl:
6109+ case DeclAttrKind::DAK_Nonisolated:
6110+ return CodeCompletionFlairBit::RareKeywordAtCurrentPosition;
6111+
6112+ default :
6113+ break ;
6114+ }
6115+ }
6116+ }
6117+ return None;
6118+ };
6119+
59426120 auto AddDeclKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind,
5943- Optional<DeclAttrKind> DAK) {
6121+ Optional<DeclAttrKind> DAK) {
59446122 if (Name == " let" || Name == " var" ) {
59456123 // Treat keywords that could be the start of a pattern specially.
59466124 return ;
@@ -5949,7 +6127,8 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink,
59496127 // FIXME: This should use canUseAttributeOnDecl.
59506128
59516129 // Remove user inaccessible keywords.
5952- if (DAK.hasValue () && DeclAttribute::isUserInaccessible (*DAK)) return ;
6130+ if (DAK.hasValue () && DeclAttribute::isUserInaccessible (*DAK))
6131+ return ;
59536132
59546133 // Remove keywords only available when concurrency is enabled.
59556134 if (DAK.hasValue () && !IsConcurrencyEnabled &&
@@ -5961,10 +6140,14 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink,
59616140 DeclAttribute::isDistributedOnly (*DAK))
59626141 return ;
59636142
5964- addKeyword (Sink, Name, Kind);
6143+ addKeyword (
6144+ Sink, Name, Kind, /* TypeAnnotation=*/ " " ,
6145+ /* TypeRelation=*/ CodeCompletionResult::ExpectedTypeRelation::NotApplicable,
6146+ getFlair (Kind, DAK));
59656147 };
59666148
5967- #define DECL_KEYWORD (kw ) AddDeclKeyword(#kw, CodeCompletionKeywordKind::kw_##kw, None);
6149+ #define DECL_KEYWORD (kw ) \
6150+ AddDeclKeyword (#kw, CodeCompletionKeywordKind::kw_##kw, None);
59686151#include " swift/Syntax/TokenKinds.def"
59696152
59706153 // Context-sensitive keywords.
@@ -5978,7 +6161,6 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink,
59786161#define CONTEXTUAL_SIMPLE_DECL_ATTR (KW, CLASS, ...) CONTEXTUAL_CASE(KW, CLASS)
59796162#include < swift/AST/Attr.def>
59806163#undef CONTEXTUAL_CASE
5981-
59826164}
59836165
59846166static void addStmtKeywords (CodeCompletionResultSink &Sink, bool MaybeFuncBody) {
@@ -6082,7 +6264,9 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
60826264 LLVM_FALLTHROUGH;
60836265 }
60846266 case CompletionKind::StmtOrExpr:
6085- addDeclKeywords (Sink, Context.LangOpts .EnableExperimentalConcurrency , Context.LangOpts .EnableExperimentalDistributed );
6267+ addDeclKeywords (Sink, CurDeclContext,
6268+ Context.LangOpts .EnableExperimentalConcurrency ,
6269+ Context.LangOpts .EnableExperimentalDistributed );
60866270 addStmtKeywords (Sink, MaybeFuncBody);
60876271 LLVM_FALLTHROUGH;
60886272 case CompletionKind::ReturnStmtExpr:
@@ -6150,7 +6334,9 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
61506334 .Default (false );
61516335 }) != ParsedKeywords.end ();
61526336 if (!HasDeclIntroducer) {
6153- addDeclKeywords (Sink, Context.LangOpts .EnableExperimentalConcurrency , Context.LangOpts .EnableExperimentalDistributed );
6337+ addDeclKeywords (Sink, CurDeclContext,
6338+ Context.LangOpts .EnableExperimentalConcurrency ,
6339+ Context.LangOpts .EnableExperimentalDistributed );
61546340 addLetVarKeywords (Sink);
61556341 }
61566342 break ;
@@ -6966,15 +7152,19 @@ void CodeCompletionCallbacksImpl::doneParsing() {
69667152
69677153 if (CurDeclContext->isTypeContext ()) {
69687154 // Override completion (CompletionKind::NominalMemberBeginning).
6969- addDeclKeywords (Sink, Context.LangOpts .EnableExperimentalConcurrency , Context.LangOpts .EnableExperimentalDistributed );
7155+ addDeclKeywords (Sink, CurDeclContext,
7156+ Context.LangOpts .EnableExperimentalConcurrency ,
7157+ Context.LangOpts .EnableExperimentalDistributed );
69707158 addLetVarKeywords (Sink);
69717159 SmallVector<StringRef, 0 > ParsedKeywords;
69727160 CompletionOverrideLookup OverrideLookup (Sink, Context, CurDeclContext,
69737161 ParsedKeywords, SourceLoc ());
69747162 OverrideLookup.getOverrideCompletions (SourceLoc ());
69757163 } else {
69767164 // Global completion (CompletionKind::PostfixExprBeginning).
6977- addDeclKeywords (Sink, Context.LangOpts .EnableExperimentalConcurrency , Context.LangOpts .EnableExperimentalDistributed );
7165+ addDeclKeywords (Sink, CurDeclContext,
7166+ Context.LangOpts .EnableExperimentalConcurrency ,
7167+ Context.LangOpts .EnableExperimentalDistributed );
69787168 addStmtKeywords (Sink, MaybeFuncBody);
69797169 addSuperKeyword (Sink);
69807170 addLetVarKeywords (Sink);
0 commit comments