Skip to content

Commit 4617bbb

Browse files
committed
[CodeCompletion] Apply 'ExprAtFileScope' when emitting keywords
1 parent 1855e1a commit 4617bbb

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;
@@ -3611,11 +3618,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36113618

36123619
void addKeyword(StringRef Name, StringRef TypeAnnotation,
36133620
CodeCompletionKeywordKind KeyKind
3614-
= CodeCompletionKeywordKind::None) {
3621+
= CodeCompletionKeywordKind::None,
3622+
CodeCompletionFlair flair = {}) {
36153623
CodeCompletionResultBuilder Builder(
36163624
Sink,
36173625
CodeCompletionResult::ResultKind::Keyword,
36183626
SemanticContextKind::None, expectedTypeContext);
3627+
Builder.addFlair(flair);
36193628
addLeadingDot(Builder);
36203629
Builder.addKeyword(Name);
36213630
Builder.setKeywordKind(KeyKind);
@@ -4365,6 +4374,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43654374

43664375
/// Add '#file', '#line', et at.
43674376
void addPoundLiteralCompletions(bool needPound) {
4377+
CodeCompletionFlair flair;
4378+
if (isCodeCompletionAtTopLevelOfLibraryFile(CurrDeclContext))
4379+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
4380+
43684381
auto addFromProto = [&](MagicIdentifierLiteralExpr::Kind magicKind,
43694382
Optional<CodeCompletionLiteralKind> literalKind) {
43704383
CodeCompletionKeywordKind kwKind;
@@ -4389,13 +4402,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43894402

43904403
if (!literalKind) {
43914404
// Pointer type
4392-
addKeyword(name, "UnsafeRawPointer", kwKind);
4405+
addKeyword(name, "UnsafeRawPointer", kwKind, flair);
43934406
return;
43944407
}
43954408

43964409
CodeCompletionResultBuilder builder(
43974410
Sink, CodeCompletionResult::ResultKind::Keyword,
43984411
SemanticContextKind::None, {});
4412+
builder.addFlair(flair);
43994413
builder.setLiteralKind(literalKind.getValue());
44004414
builder.setKeywordKind(kwKind);
44014415
builder.addBaseName(name);
@@ -4417,6 +4431,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44174431
void addValueLiteralCompletions() {
44184432
auto &context = CurrDeclContext->getASTContext();
44194433

4434+
CodeCompletionFlair flair;
4435+
if (isCodeCompletionAtTopLevelOfLibraryFile(CurrDeclContext))
4436+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
4437+
44204438
auto addFromProto = [&](
44214439
CodeCompletionLiteralKind kind,
44224440
llvm::function_ref<void(CodeCompletionResultBuilder &)> consumer,
@@ -4425,6 +4443,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44254443
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
44264444
SemanticContextKind::None, {});
44274445
builder.setLiteralKind(kind);
4446+
builder.addFlair(flair);
44284447

44294448
consumer(builder);
44304449
addTypeRelationFromProtocol(builder, kind);
@@ -4497,6 +4516,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
44974516
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
44984517
SemanticContextKind::None, {});
44994518
builder.setLiteralKind(LK::Tuple);
4519+
builder.addFlair(flair);
45004520

45014521
builder.addLeftParen();
45024522
builder.addSimpleNamedParameter("values");
@@ -6051,8 +6071,7 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
60516071

60526072
auto getFlair = [&](CodeCompletionKeywordKind Kind,
60536073
Optional<DeclAttrKind> DAK) -> CodeCompletionFlair {
6054-
if (isCodeCompletionAtTopLevel(DC) &&
6055-
!DC->getParentSourceFile()->isScriptMode()) {
6074+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
60566075
// Type decls are common in library file top-level.
60576076
if (isTypeDeclIntroducer(Kind, DAK))
60586077
return CodeCompletionFlairBit::CommonKeywordAtCurrentPosition;
@@ -6165,11 +6184,20 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
61656184
#undef CONTEXTUAL_CASE
61666185
}
61676186

6168-
static void addStmtKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) {
6187+
static void addStmtKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
6188+
bool MaybeFuncBody) {
6189+
CodeCompletionFlair flair;
6190+
// Starting a statement at top-level in non-script files is invalid.
6191+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
6192+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
6193+
}
6194+
61696195
auto AddStmtKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) {
61706196
if (!MaybeFuncBody && Kind == CodeCompletionKeywordKind::kw_return)
61716197
return;
6172-
addKeyword(Sink, Name, Kind);
6198+
addKeyword(Sink, Name, Kind, "",
6199+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable,
6200+
flair);
61736201
};
61746202
#define STMT_KEYWORD(kw) AddStmtKeyword(#kw, CodeCompletionKeywordKind::kw_##kw);
61756203
#include "swift/Syntax/TokenKinds.def"
@@ -6195,12 +6223,22 @@ static void addObserverKeywords(CodeCompletionResultSink &Sink) {
61956223
addKeyword(Sink, "didSet", CodeCompletionKeywordKind::None);
61966224
}
61976225

6198-
static void addExprKeywords(CodeCompletionResultSink &Sink) {
6226+
static void addExprKeywords(CodeCompletionResultSink &Sink, DeclContext *DC) {
6227+
// Expression is invalid at top-level of non-script files.
6228+
CodeCompletionFlair flair;
6229+
if (isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
6230+
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
6231+
}
6232+
61996233
// Expr keywords.
6200-
addKeyword(Sink, "try", CodeCompletionKeywordKind::kw_try);
6201-
addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try);
6202-
addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try);
6203-
addKeyword(Sink, "await", CodeCompletionKeywordKind::None);
6234+
addKeyword(Sink, "try", CodeCompletionKeywordKind::kw_try, "",
6235+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6236+
addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try, "",
6237+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6238+
addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try, "",
6239+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
6240+
addKeyword(Sink, "await", CodeCompletionKeywordKind::None, "",
6241+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable, flair);
62046242
}
62056243

62066244
static void addOpaqueTypeKeyword(CodeCompletionResultSink &Sink) {
@@ -6269,15 +6307,15 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
62696307
addDeclKeywords(Sink, CurDeclContext,
62706308
Context.LangOpts.EnableExperimentalConcurrency,
62716309
Context.LangOpts.EnableExperimentalDistributed);
6272-
addStmtKeywords(Sink, MaybeFuncBody);
6310+
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
62736311
LLVM_FALLTHROUGH;
62746312
case CompletionKind::ReturnStmtExpr:
62756313
case CompletionKind::YieldStmtExpr:
62766314
case CompletionKind::PostfixExprBeginning:
62776315
case CompletionKind::ForEachSequence:
62786316
addSuperKeyword(Sink);
62796317
addLetVarKeywords(Sink);
6280-
addExprKeywords(Sink);
6318+
addExprKeywords(Sink, CurDeclContext);
62816319
addAnyTypeKeyword(Sink, CurDeclContext->getASTContext().TheAnyType);
62826320
break;
62836321

@@ -6481,19 +6519,6 @@ static void addConditionalCompilationFlags(ASTContext &Ctx,
64816519

64826520
static void postProcessResults(ArrayRef<CodeCompletionResult *> results,
64836521
CompletionKind Kind, DeclContext *DC) {
6484-
auto isExprKeyword = [](const CodeCompletionResult *result) {
6485-
if (result->getKind() != CodeCompletionResult::ResultKind::Keyword)
6486-
return false;
6487-
switch (result->getKeywordKind()) {
6488-
#define POUND_DIRECTIVE_KEYWORD(kw)
6489-
#define POUND_CONFIG(kw)
6490-
#define POUND_KEYWORD(kw) case CodeCompletionKeywordKind::pound_##kw:
6491-
#include "swift/Syntax/TokenKinds.def"
6492-
return true;
6493-
default:
6494-
return false;
6495-
}
6496-
};
64976522
for (CodeCompletionResult *result : results) {
64986523
auto flair = result->getFlair();
64996524

@@ -6511,11 +6536,8 @@ static void postProcessResults(ArrayRef<CodeCompletionResult *> results,
65116536

65126537
// Starting a statement at top-level in non-script files is invalid.
65136538
if (Kind == CompletionKind::StmtOrExpr &&
6514-
isCodeCompletionAtTopLevel(DC) &&
6515-
!DC->getParentSourceFile()->isScriptMode() &&
6516-
(result->getKind() == CodeCompletionResult::ResultKind::Declaration ||
6517-
result->getKind() == CodeCompletionResult::ResultKind::Literal ||
6518-
isExprKeyword(result))) {
6539+
result->getKind() == CodeCompletionResult::ResultKind::Declaration &&
6540+
isCodeCompletionAtTopLevelOfLibraryFile(DC)) {
65196541
flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope;
65206542
}
65216543
result->setFlair(flair);
@@ -7006,7 +7028,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
70067028

70077029
// Add any keywords that can be used in an argument expr position.
70087030
addSuperKeyword(CompletionContext.getResultSink());
7009-
addExprKeywords(CompletionContext.getResultSink());
7031+
addExprKeywords(CompletionContext.getResultSink(), CurDeclContext);
70107032

70117033
DoPostfixExprBeginning();
70127034
}
@@ -7152,7 +7174,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
71527174

71537175
// Add any keywords that can be used in an argument expr position.
71547176
addSuperKeyword(CompletionContext.getResultSink());
7155-
addExprKeywords(CompletionContext.getResultSink());
7177+
addExprKeywords(CompletionContext.getResultSink(), CurDeclContext);
71567178

71577179
DoPostfixExprBeginning();
71587180
}
@@ -7208,10 +7230,10 @@ void CodeCompletionCallbacksImpl::doneParsing() {
72087230
addDeclKeywords(Sink, CurDeclContext,
72097231
Context.LangOpts.EnableExperimentalConcurrency,
72107232
Context.LangOpts.EnableExperimentalDistributed);
7211-
addStmtKeywords(Sink, MaybeFuncBody);
7233+
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
72127234
addSuperKeyword(Sink);
72137235
addLetVarKeywords(Sink);
7214-
addExprKeywords(Sink);
7236+
addExprKeywords(Sink, CurDeclContext);
72157237
addAnyTypeKeyword(Sink, Context.TheAnyType);
72167238
DoPostfixExprBeginning();
72177239
}

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)