From fd542e267c6fa9dbd2364dca84e5918c667ffe6b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 18 Mar 2019 16:58:52 -0700 Subject: [PATCH] [CodeCompletion] 'case' keyword completion at the top of 'switch' stmt rdar://problem/35943849 --- include/swift/IDE/CodeCompletion.h | 1 + include/swift/Parse/CodeCompletionCallbacks.h | 3 +++ lib/IDE/CodeCompletion.cpp | 22 ++++++++++++++++--- lib/Parse/ParseStmt.cpp | 5 +++++ test/IDE/complete_keywords.swift | 16 ++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index bf391272600ed..5cfa91ebb0af5 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -492,6 +492,7 @@ enum class CompletionKind { TypeSimpleBeginning, TypeIdentifierWithDot, TypeIdentifierWithoutDot, + CaseStmtKeyword, CaseStmtBeginning, CaseStmtDotPrefix, NominalMemberBeginning, diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index ebe19822ff1e6..9079a293c4842 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -165,6 +165,9 @@ class CodeCompletionCallbacks { /// Complete a given type-identifier when there is no trailing dot. virtual void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) {}; + /// Complete the beginning of a case statement at the top of switch stmt. + virtual void completeCaseStmtKeyword() {}; + /// Complete at the beginning of a case stmt pattern. virtual void completeCaseStmtBeginning() {}; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 1490fb4ff6c4b..e9ab698da0252 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1348,6 +1348,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override; void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override; + void completeCaseStmtKeyword() override; void completeCaseStmtBeginning() override; void completeCaseStmtDotPrefix() override; void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) override; @@ -4417,6 +4418,11 @@ void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot( CurDeclContext = P.CurDeclContext; } +void CodeCompletionCallbacksImpl::completeCaseStmtKeyword() { + Kind = CompletionKind::CaseStmtKeyword; + CurDeclContext = P.CurDeclContext; +} + void CodeCompletionCallbacksImpl::completeCaseStmtBeginning() { assert(!InEnumElementRawValue); @@ -4598,6 +4604,11 @@ static void addStmtKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) #include "swift/Syntax/TokenKinds.def" } +static void addCaseStmtKeywords(CodeCompletionResultSink &Sink) { + addKeyword(Sink, "case", CodeCompletionKeywordKind::kw_case); + addKeyword(Sink, "default", CodeCompletionKeywordKind::kw_default); +} + static void addLetVarKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "let", CodeCompletionKeywordKind::kw_let); addKeyword(Sink, "var", CodeCompletionKeywordKind::kw_var); @@ -4687,6 +4698,10 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, addAnyTypeKeyword(Sink); break; + case CompletionKind::CaseStmtKeyword: + addCaseStmtKeywords(Sink); + break; + case CompletionKind::PostfixExpr: case CompletionKind::PostfixExprParen: case CompletionKind::SuperExpr: @@ -5189,12 +5204,13 @@ void CodeCompletionCallbacksImpl::doneParsing() { } } break; - case CompletionKind::AfterIfStmtElse: - // Handled earlier by keyword completions. - break; case CompletionKind::PrecedenceGroup: Lookup.getPrecedenceGroupCompletions(SyntxKind); break; + case CompletionKind::AfterIfStmtElse: + case CompletionKind::CaseStmtKeyword: + // Handled earlier by keyword completions. + break; } for (auto &Request: Lookup.RequestedCachedResults) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 116211413bb65..452db91348449 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2274,6 +2274,11 @@ Parser::parseStmtCases(SmallVectorImpl &cases, bool IsActive) { if (auto PDD = PoundDiagnosticResult.getPtrOrNull()) { cases.emplace_back(PDD); } + } else if (Tok.is(tok::code_complete)) { + if (CodeCompletion) + CodeCompletion->completeCaseStmtKeyword(); + consumeToken(tok::code_complete); + return makeParserCodeCompletionStatus(); } else { // If there are non-case-label statements at the start of the switch body, // raise an error and recover by discarding them. diff --git a/test/IDE/complete_keywords.swift b/test/IDE/complete_keywords.swift index df191e55e86f8..8c648c6abec13 100644 --- a/test/IDE/complete_keywords.swift +++ b/test/IDE/complete_keywords.swift @@ -90,6 +90,9 @@ // RUN: %FileCheck %s -check-prefix=KW_EXPR < %t.expr6 // RUN: %FileCheck %s -check-prefix=KW_EXPR_NEG < %t.expr6 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SWITCH_TOP | %FileCheck %s -check-prefix=KW_CASE +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SWITCH_IN_CASE | %FileCheck %s -check-prefix=KW_CASE + // KW_RETURN: Keyword[return]/None: return{{; name=.+$}} // KW_NO_RETURN-NOT: Keyword[return] @@ -401,3 +404,16 @@ func inExpr5() { func inExpr6() -> Int { return #^EXPR_6^# } + +func inSwitch(val: Int) { + switch val { + #^SWITCH_TOP^# + case 1: + foo() + #^SWITCH_IN_CASE^# + } +// Begin completions +// KW_CASE-DAG: Keyword[case]/None: case; name=case +// KW_CASE-DAG: Keyword[default]/None: default; name=default +// End completions +}