Skip to content

Commit 2281e46

Browse files
committed
[CodeCompletion] Apply 'ExprAtFileScope' when emitting keywords
(cherry picked from commit 4617bbb)
1 parent 2024751 commit 2281e46

File tree

2 files changed

+84
-50
lines changed

2 files changed

+84
-50
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,14 +1848,14 @@ static bool canDeclContextHandleAsync(const DeclContext *DC) {
18481848
/// #false#
18491849
/// }
18501850
/// }
1851-
static bool isCodeCompletionAtTopLevel(DeclContext *DC) {
1851+
static bool isCodeCompletionAtTopLevel(const DeclContext *DC) {
18521852
if (DC->isModuleScopeContext())
18531853
return true;
18541854

18551855
// CC token at top-level is parsed as an expression. If the only element
18561856
// body of the TopLevelCodeDecl is a CodeCompletionExpr without a base
18571857
// expression, the user might be writing a top-level declaration.
1858-
if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(DC)) {
1858+
if (const TopLevelCodeDecl *TLCD = dyn_cast<const TopLevelCodeDecl>(DC)) {
18591859
auto body = TLCD->getBody();
18601860
if (!body || body->empty())
18611861
return true;
@@ -1897,6 +1897,13 @@ static bool isCompletionDeclContextLocalContext(DeclContext *DC) {
18971897
return true;
18981898
}
18991899

1900+
/// Return \c true if the completion happens at top-level of a library file.
1901+
static bool isCodeCompletionAtTopLevelOfLibraryFile(const DeclContext *DC) {
1902+
if (DC->getParentSourceFile()->isScriptMode())
1903+
return false;
1904+
return isCodeCompletionAtTopLevel(DC);
1905+
}
1906+
19001907
/// Build completions by doing visible decl lookup from a context.
19011908
class CompletionLookup final : public swift::VisibleDeclConsumer {
19021909
CodeCompletionResultSink &Sink;
@@ -3606,11 +3613,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36063613

36073614
void addKeyword(StringRef Name, StringRef TypeAnnotation,
36083615
CodeCompletionKeywordKind KeyKind
3609-
= CodeCompletionKeywordKind::None) {
3616+
= CodeCompletionKeywordKind::None,
3617+
CodeCompletionFlair flair = {}) {
36103618
CodeCompletionResultBuilder Builder(
36113619
Sink,
36123620
CodeCompletionResult::ResultKind::Keyword,
36133621
SemanticContextKind::None, expectedTypeContext);
3622+
Builder.addFlair(flair);
36143623
addLeadingDot(Builder);
36153624
Builder.addKeyword(Name);
36163625
Builder.setKeywordKind(KeyKind);
@@ -4360,6 +4369,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43604369

43614370
/// Add '#file', '#line', et at.
43624371
void addPoundLiteralCompletions(bool needPound) {
4372+
CodeCompletionFlair flair;
4373+
if (isCodeCompletionAtTopLevelOfLibraryFile(CurrDeclContext))
4374+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
4375+
43634376
auto addFromProto = [&](MagicIdentifierLiteralExpr::Kind magicKind,
43644377
Optional<CodeCompletionLiteralKind> literalKind) {
43654378
CodeCompletionKeywordKind kwKind;
@@ -4384,13 +4397,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43844397

43854398
if (!literalKind) {
43864399
// Pointer type
4387-
addKeyword(name, "UnsafeRawPointer", kwKind);
4400+
addKeyword(name, "UnsafeRawPointer", kwKind, flair);
43884401
return;
43894402
}
43904403

43914404
CodeCompletionResultBuilder builder(
43924405
Sink, CodeCompletionResult::ResultKind::Keyword,
43934406
SemanticContextKind::None, {});
4407+
builder.addFlair(flair);
43944408
builder.setLiteralKind(literalKind.getValue());
43954409
builder.setKeywordKind(kwKind);
43964410
builder.addBaseName(name);
@@ -4412,6 +4426,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44124426
void addValueLiteralCompletions() {
44134427
auto &context = CurrDeclContext->getASTContext();
44144428

4429+
CodeCompletionFlair flair;
4430+
if (isCodeCompletionAtTopLevelOfLibraryFile(CurrDeclContext))
4431+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
4432+
44154433
auto addFromProto = [&](
44164434
CodeCompletionLiteralKind kind,
44174435
llvm::function_ref<void(CodeCompletionResultBuilder &)> consumer,
@@ -4420,6 +4438,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44204438
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
44214439
SemanticContextKind::None, {});
44224440
builder.setLiteralKind(kind);
4441+
builder.addFlair(flair);
44234442

44244443
consumer(builder);
44254444
addTypeRelationFromProtocol(builder, kind);
@@ -4492,6 +4511,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44924511
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
44934512
SemanticContextKind::None, {});
44944513
builder.setLiteralKind(LK::Tuple);
4514+
builder.addFlair(flair);
44954515

44964516
builder.addLeftParen();
44974517
builder.addSimpleNamedParameter("values");
@@ -6038,8 +6058,7 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
60386058

60396059
auto getFlair = [&](CodeCompletionKeywordKind Kind,
60406060
Optional<DeclAttrKind> DAK) -> CodeCompletionFlair {
6041-
if (isCodeCompletionAtTopLevel(DC) &&
6042-
!DC->getParentSourceFile()->isScriptMode()) {
6061+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
60436062
// Type decls are common in library file top-level.
60446063
if (isTypeDeclIntroducer(Kind, DAK))
60456064
return CodeCompletionFlairBit::CommonKeywordAtCurrentPosition;
@@ -6147,11 +6166,20 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
61476166
#undef CONTEXTUAL_CASE
61486167
}
61496168

6150-
static void addStmtKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) {
6169+
static void addStmtKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
6170+
bool MaybeFuncBody) {
6171+
CodeCompletionFlair flair;
6172+
// Starting a statement at top-level in non-script files is invalid.
6173+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
6174+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
6175+
}
6176+
61516177
auto AddStmtKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) {
61526178
if (!MaybeFuncBody && Kind == CodeCompletionKeywordKind::kw_return)
61536179
return;
6154-
addKeyword(Sink, Name, Kind);
6180+
addKeyword(Sink, Name, Kind, "",
6181+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable,
6182+
flair);
61556183
};
61566184
#define STMT_KEYWORD(kw) AddStmtKeyword(#kw, CodeCompletionKeywordKind::kw_##kw);
61576185
#include "swift/Syntax/TokenKinds.def"
@@ -6177,12 +6205,22 @@ static void addObserverKeywords(CodeCompletionResultSink &Sink) {
61776205
addKeyword(Sink, "didSet", CodeCompletionKeywordKind::None);
61786206
}
61796207

6180-
static void addExprKeywords(CodeCompletionResultSink &Sink) {
6208+
static void addExprKeywords(CodeCompletionResultSink &Sink, DeclContext *DC) {
6209+
// Expression is invalid at top-level of non-script files.
6210+
CodeCompletionFlair flair;
6211+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
6212+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
6213+
}
6214+
61816215
// Expr keywords.
6182-
addKeyword(Sink, "try", CodeCompletionKeywordKind::kw_try);
6183-
addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try);
6184-
addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try);
6185-
addKeyword(Sink, "await", CodeCompletionKeywordKind::None);
6216+
addKeyword(Sink, "try", CodeCompletionKeywordKind::kw_try, "",
6217+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6218+
addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try, "",
6219+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6220+
addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try, "",
6221+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6222+
addKeyword(Sink, "await", CodeCompletionKeywordKind::None, "",
6223+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
61866224
}
61876225

61886226
static void addOpaqueTypeKeyword(CodeCompletionResultSink &Sink) {
@@ -6250,15 +6288,15 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
62506288
case CompletionKind::StmtOrExpr:
62516289
addDeclKeywords(Sink, CurDeclContext,
62526290
Context.LangOpts.EnableExperimentalConcurrency);
6253-
addStmtKeywords(Sink, MaybeFuncBody);
6291+
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
62546292
LLVM_FALLTHROUGH;
62556293
case CompletionKind::ReturnStmtExpr:
62566294
case CompletionKind::YieldStmtExpr:
62576295
case CompletionKind::PostfixExprBeginning:
62586296
case CompletionKind::ForEachSequence:
62596297
addSuperKeyword(Sink);
62606298
addLetVarKeywords(Sink);
6261-
addExprKeywords(Sink);
6299+
addExprKeywords(Sink, CurDeclContext);
62626300
addAnyTypeKeyword(Sink, CurDeclContext->getASTContext().TheAnyType);
62636301
break;
62646302

@@ -6461,19 +6499,6 @@ static void addConditionalCompilationFlags(ASTContext &Ctx,
64616499

64626500
static void postProcessResults(ArrayRef<CodeCompletionResult *> results,
64636501
CompletionKind Kind, DeclContext *DC) {
6464-
auto isExprKeyword = [](const CodeCompletionResult *result) {
6465-
if (result->getKind() != CodeCompletionResult::ResultKind::Keyword)
6466-
return false;
6467-
switch (result->getKeywordKind()) {
6468-
#define POUND_DIRECTIVE_KEYWORD(kw)
6469-
#define POUND_CONFIG(kw)
6470-
#define POUND_KEYWORD(kw) case CodeCompletionKeywordKind::pound_##kw:
6471-
#include "swift/Syntax/TokenKinds.def"
6472-
return true;
6473-
default:
6474-
return false;
6475-
}
6476-
};
64776502
for (CodeCompletionResult *result : results) {
64786503
auto flair = result->getFlair();
64796504

@@ -6491,11 +6516,8 @@ static void postProcessResults(ArrayRef<CodeCompletionResult *> results,
64916516

64926517
// Starting a statement at top-level in non-script files is invalid.
64936518
if (Kind == CompletionKind::StmtOrExpr &&
6494-
isCodeCompletionAtTopLevel(DC) &&
6495-
!DC->getParentSourceFile()->isScriptMode() &&
6496-
(result->getKind() == CodeCompletionResult::ResultKind::Declaration ||
6497-
result->getKind() == CodeCompletionResult::ResultKind::Literal ||
6498-
isExprKeyword(result))) {
6519+
result->getKind() == CodeCompletionResult::ResultKind::Declaration &&
6520+
isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
64996521
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
65006522
}
65016523
result->setFlair(flair);
@@ -6986,7 +7008,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
69867008

69877009
// Add any keywords that can be used in an argument expr position.
69887010
addSuperKeyword(CompletionContext.getResultSink());
6989-
addExprKeywords(CompletionContext.getResultSink());
7011+
addExprKeywords(CompletionContext.getResultSink(), CurDeclContext);
69907012

69917013
DoPostfixExprBeginning();
69927014
}
@@ -7132,7 +7154,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
71327154

71337155
// Add any keywords that can be used in an argument expr position.
71347156
addSuperKeyword(CompletionContext.getResultSink());
7135-
addExprKeywords(CompletionContext.getResultSink());
7157+
addExprKeywords(CompletionContext.getResultSink(), CurDeclContext);
71367158

71377159
DoPostfixExprBeginning();
71387160
}
@@ -7186,10 +7208,10 @@ void CodeCompletionCallbacksImpl::doneParsing() {
71867208
// Global completion (CompletionKind::PostfixExprBeginning).
71877209
addDeclKeywords(Sink, CurDeclContext,
71887210
Context.LangOpts.EnableExperimentalConcurrency);
7189-
addStmtKeywords(Sink, MaybeFuncBody);
7211+
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
71907212
addSuperKeyword(Sink);
71917213
addLetVarKeywords(Sink);
7192-
addExprKeywords(Sink);
7214+
addExprKeywords(Sink, CurDeclContext);
71937215
addAnyTypeKeyword(Sink, Context.TheAnyType);
71947216
DoPostfixExprBeginning();
71957217
}

test/IDE/complete_at_top_level_library.swift

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,25 @@ protocol MyProtocol {}
4949
// LIBRARY-DAG: Keyword/None: unowned; name=unowned
5050
// LIBRARY-DAG: Keyword/None: indirect; name=indirect
5151
// LIBRARY-DAG: Keyword/None: nonisolated; name=nonisolated
52-
// LIBRARY-DAG: Keyword[defer]/None: defer; name=defer
53-
// LIBRARY-DAG: Keyword[if]/None: if; name=if
54-
// LIBRARY-DAG: Keyword[guard]/None: guard; name=guard
55-
// LIBRARY-DAG: Keyword[do]/None: do; name=do
56-
// LIBRARY-DAG: Keyword[repeat]/None: repeat; name=repeat
57-
// LIBRARY-DAG: Keyword[else]/None: else; name=else
58-
// LIBRARY-DAG: Keyword[for]/None: for; name=for
59-
// LIBRARY-DAG: Keyword[in]/None: in; name=in
60-
// LIBRARY-DAG: Keyword[while]/None: while; name=while
61-
// LIBRARY-DAG: Keyword[break]/None: break; name=break
62-
// LIBRARY-DAG: Keyword[continue]/None: continue; name=continue
63-
// LIBRARY-DAG: Keyword[fallthrough]/None: fallthrough; name=fallthrough
64-
// LIBRARY-DAG: Keyword[switch]/None: switch; name=switch
52+
// LIBRARY-DAG: Keyword[defer]/None/Flair[ExprAtFileScope]: defer; name=defer
53+
// LIBRARY-DAG: Keyword[if]/None/Flair[ExprAtFileScope]: if; name=if
54+
// LIBRARY-DAG: Keyword[guard]/None/Flair[ExprAtFileScope]: guard; name=guard
55+
// LIBRARY-DAG: Keyword[do]/None/Flair[ExprAtFileScope]: do; name=do
56+
// LIBRARY-DAG: Keyword[repeat]/None/Flair[ExprAtFileScope]: repeat; name=repeat
57+
// LIBRARY-DAG: Keyword[else]/None/Flair[ExprAtFileScope]: else; name=else
58+
// LIBRARY-DAG: Keyword[for]/None/Flair[ExprAtFileScope]: for; name=for
59+
// LIBRARY-DAG: Keyword[in]/None/Flair[ExprAtFileScope]: in; name=in
60+
// LIBRARY-DAG: Keyword[while]/None/Flair[ExprAtFileScope]: while; name=while
61+
// LIBRARY-DAG: Keyword[break]/None/Flair[ExprAtFileScope]: break; name=break
62+
// LIBRARY-DAG: Keyword[continue]/None/Flair[ExprAtFileScope]: continue; name=continue
63+
// LIBRARY-DAG: Keyword[fallthrough]/None/Flair[ExprAtFileScope]: fallthrough; name=fallthrough
64+
// LIBRARY-DAG: Keyword[switch]/None/Flair[ExprAtFileScope]: switch; name=switch
65+
// LIBRARY-DAG: Keyword[let]/None: let; name=let
66+
// LIBRARY-DAG: Keyword[var]/None: var; name=var
67+
// LIBRARY-DAG: Keyword[try]/None/Flair[ExprAtFileScope]: try; name=try
68+
// LIBRARY-DAG: Keyword[try]/None/Flair[ExprAtFileScope]: try!; name=try!
69+
// LIBRARY-DAG: Keyword[try]/None/Flair[ExprAtFileScope]: try?; name=try?
70+
// LIBRARY-DAG: Keyword/None/Flair[ExprAtFileScope]: await; name=await
6571
// LIBRARY-DAG: Literal[Integer]/None/Flair[ExprAtFileScope]: 0[#Int#]; name=0
6672
// LIBRARY-DAG: Literal[Boolean]/None/Flair[ExprAtFileScope]: true[#Bool#]; name=true
6773
// LIBRARY-DAG: Literal[Boolean]/None/Flair[ExprAtFileScope]: false[#Bool#]; name=false
@@ -133,6 +139,12 @@ protocol MyProtocol {}
133139
// SCRIPT-DAG: Keyword[continue]/None: continue; name=continue
134140
// SCRIPT-DAG: Keyword[fallthrough]/None: fallthrough; name=fallthrough
135141
// SCRIPT-DAG: Keyword[switch]/None: switch; name=switch
142+
// SCRIPT-DAG: Keyword[let]/None: let; name=let
143+
// SCRIPT-DAG: Keyword[var]/None: var; name=var
144+
// SCRIPT-DAG: Keyword[try]/None: try; name=try
145+
// SCRIPT-DAG: Keyword[try]/None: try!; name=try!
146+
// SCRIPT-DAG: Keyword[try]/None: try?; name=try?
147+
// SCRIPT-DAG: Keyword/None: await; name=await
136148
// SCRIPT-DAG: Literal[Integer]/None: 0[#Int#]; name=0
137149
// SCRIPT-DAG: Literal[Boolean]/None: true[#Bool#]; name=true
138150
// SCRIPT-DAG: Literal[Boolean]/None: false[#Bool#]; name=false

0 commit comments

Comments
 (0)