Skip to content

Commit

Permalink
[CodeCompletion] Split literals out into their own completion kind
Browse files Browse the repository at this point in the history
For rdar://problem/21923069

Swift SVN r32906
  • Loading branch information
benlangmuir committed Oct 27, 2015
1 parent 9662523 commit 54a28a4
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 62 deletions.
44 changes: 39 additions & 5 deletions include/swift/IDE/CodeCompletion.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ enum class CodeCompletionDeclKind {
GlobalVar,
};

enum class CodeCompletionLiteralKind {
ArrayLiteral,
BooleanLiteral,
_ColorLiteral,
DictionaryLiteral,
FloatLiteral,
IntegerLiteral,
NilLiteral,
StringLiteral,
Tuple,
};

enum class CompletionKind {
None,
Import,
Expand Down Expand Up @@ -437,7 +449,8 @@ class CodeCompletionResult {
enum ResultKind {
Declaration,
Keyword,
Pattern
Pattern,
Literal,
};

/// Describing the relationship between the type of the completion results and
Expand All @@ -460,7 +473,7 @@ class CodeCompletionResult {

private:
unsigned Kind : 2;
unsigned AssociatedDeclKind : 8;
unsigned AssociatedDeclOrLiteralKind : 8;
unsigned SemanticContext : 3;
unsigned NotRecommended : 1;

Expand Down Expand Up @@ -495,6 +508,21 @@ class CodeCompletionResult {
assert(CompletionString);
}

/// Constructs a \c Literal result.
///
/// \note The caller must ensure \c CodeCompletionString outlives this result.
CodeCompletionResult(CodeCompletionLiteralKind LiteralKind,
SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
ExpectedTypeRelation TypeDistance)
: Kind(Literal), SemanticContext(unsigned(SemanticContext)),
NotRecommended(false), NumBytesToErase(NumBytesToErase),
CompletionString(CompletionString), TypeDistance(TypeDistance) {
AssociatedDeclOrLiteralKind = static_cast<unsigned>(LiteralKind);
assert(CompletionString);
}

/// Constructs a \c Declaration result.
///
/// \note The caller must ensure \c CodeCompletionString and any StringRef
Expand All @@ -514,7 +542,8 @@ class CodeCompletionResult {
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
TypeDistance(TypeDistance) {
assert(AssociatedDecl && "should have a decl");
AssociatedDeclKind = unsigned(getCodeCompletionDeclKind(AssociatedDecl));
AssociatedDeclOrLiteralKind =
unsigned(getCodeCompletionDeclKind(AssociatedDecl));
assert(CompletionString);
}

Expand All @@ -530,7 +559,7 @@ class CodeCompletionResult {
NotRecommended(NotRecommended), NumBytesToErase(NumBytesToErase),
CompletionString(CompletionString), ModuleName(ModuleName),
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs) {
AssociatedDeclKind = static_cast<unsigned>(DeclKind);
AssociatedDeclOrLiteralKind = static_cast<unsigned>(DeclKind);
assert(CompletionString);
TypeDistance = ExpectedTypeRelation::Unrelated;
}
Expand All @@ -539,7 +568,12 @@ class CodeCompletionResult {

CodeCompletionDeclKind getAssociatedDeclKind() const {
assert(getKind() == Declaration);
return static_cast<CodeCompletionDeclKind>(AssociatedDeclKind);
return static_cast<CodeCompletionDeclKind>(AssociatedDeclOrLiteralKind);
}

CodeCompletionLiteralKind getLiteralKind() const {
assert(getKind() == Literal);
return static_cast<CodeCompletionLiteralKind>(AssociatedDeclOrLiteralKind);
}

bool isOperator() const {
Expand Down
96 changes: 80 additions & 16 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,38 @@ void CodeCompletionResult::print(raw_ostream &OS) const {
case ResultKind::Pattern:
Prefix.append("Pattern");
break;
case ResultKind::Literal:
Prefix.append("Literal");
switch (getLiteralKind()) {
case CodeCompletionLiteralKind::ArrayLiteral:
Prefix.append("[Array]");
break;
case CodeCompletionLiteralKind::BooleanLiteral:
Prefix.append("[Boolean]");
break;
case CodeCompletionLiteralKind::_ColorLiteral:
Prefix.append("[_Color]");
break;
case CodeCompletionLiteralKind::DictionaryLiteral:
Prefix.append("[Dictionary]");
break;
case CodeCompletionLiteralKind::FloatLiteral:
Prefix.append("[Float]");
break;
case CodeCompletionLiteralKind::IntegerLiteral:
Prefix.append("[Integer]");
break;
case CodeCompletionLiteralKind::NilLiteral:
Prefix.append("[Nil]");
break;
case CodeCompletionLiteralKind::StringLiteral:
Prefix.append("[String]");
break;
case CodeCompletionLiteralKind::Tuple:
Prefix.append("[Tuple]");
break;
}
break;
}
Prefix.append("/");
switch (getSemanticContext()) {
Expand Down Expand Up @@ -620,6 +652,12 @@ CodeCompletionResult *CodeCompletionResultBuilder::takeResult() {
case CodeCompletionResult::ResultKind::Pattern:
return new (*Sink.Allocator) CodeCompletionResult(
Kind, SemanticContext, NumBytesToErase, CCS, ExpectedTypeRelation);

case CodeCompletionResult::ResultKind::Literal:
assert(LiteralKind.hasValue());
return new (*Sink.Allocator)
CodeCompletionResult(*LiteralKind, SemanticContext, NumBytesToErase,
CCS, ExpectedTypeRelation);
}
}

Expand Down Expand Up @@ -1055,6 +1093,30 @@ static Type getReturnTypeFromContext(const DeclContext *DC) {
return Type();
}

static KnownProtocolKind
protocolForLiteralKind(CodeCompletionLiteralKind kind) {
switch (kind) {
case CodeCompletionLiteralKind::ArrayLiteral:
return KnownProtocolKind::ArrayLiteralConvertible;
case CodeCompletionLiteralKind::BooleanLiteral:
return KnownProtocolKind::BooleanLiteralConvertible;
case CodeCompletionLiteralKind::_ColorLiteral:
return KnownProtocolKind::_ColorLiteralConvertible;
case CodeCompletionLiteralKind::DictionaryLiteral:
return KnownProtocolKind::DictionaryLiteralConvertible;
case CodeCompletionLiteralKind::FloatLiteral:
return KnownProtocolKind::FloatLiteralConvertible;
case CodeCompletionLiteralKind::IntegerLiteral:
return KnownProtocolKind::IntegerLiteralConvertible;
case CodeCompletionLiteralKind::NilLiteral:
return KnownProtocolKind::NilLiteralConvertible;
case CodeCompletionLiteralKind::StringLiteral:
return KnownProtocolKind::StringLiteralConvertible;
case CodeCompletionLiteralKind::Tuple:
llvm_unreachable("no such protocol kind");
}
}

/// Build completions by doing visible decl lookup from a context.
class CompletionLookup final : public swift::VisibleDeclConsumer {
CodeCompletionResultSink &Sink;
Expand Down Expand Up @@ -2648,19 +2710,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
auto *module = CurrDeclContext->getParentModule();

auto addFromProto = [&](
KnownProtocolKind kind, StringRef defaultTypeName,
CodeCompletionLiteralKind kind, StringRef defaultTypeName,
llvm::function_ref<void(CodeCompletionResultBuilder &)> consumer,
bool isKeyword = false) {
auto completionKind = isKeyword ? CodeCompletionResult::Keyword
: CodeCompletionResult::Pattern;

CodeCompletionResultBuilder builder(Sink, completionKind,
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
SemanticContextKind::None, {});
builder.setLiteralKind(kind);

consumer(builder);

// Check for matching ExpectedTypes.
auto *P = context.getProtocol(kind);
auto *P = context.getProtocol(protocolForLiteralKind(kind));
bool foundConformance = false;
for (auto T : ExpectedTypes) {
if (!T)
Expand All @@ -2682,36 +2743,36 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

// FIXME: the pedantically correct way is to resolve Swift.*LiteralType.

using KPK = KnownProtocolKind;
using LK = CodeCompletionLiteralKind;
using Builder = CodeCompletionResultBuilder;

// Add literal completions that conform to specific protocols.
addFromProto(KPK::IntegerLiteralConvertible, "Int", [](Builder &builder) {
addFromProto(LK::IntegerLiteral, "Int", [](Builder &builder) {
builder.addTextChunk("0");
});
addFromProto(KPK::FloatLiteralConvertible, "Double", [](Builder &builder) {
addFromProto(LK::FloatLiteral, "Double", [](Builder &builder) {
builder.addTextChunk("0.0");
});
addFromProto(KPK::BooleanLiteralConvertible, "Bool", [](Builder &builder) {
addFromProto(LK::BooleanLiteral, "Bool", [](Builder &builder) {
builder.addTextChunk("true");
}, /*isKeyword=*/true);
addFromProto(KPK::BooleanLiteralConvertible, "Bool", [](Builder &builder) {
addFromProto(LK::BooleanLiteral, "Bool", [](Builder &builder) {
builder.addTextChunk("false");
}, /*isKeyword=*/true);
addFromProto(KPK::NilLiteralConvertible, "", [](Builder &builder) {
addFromProto(LK::NilLiteral, "", [](Builder &builder) {
builder.addTextChunk("nil");
}, /*isKeyword=*/true);
addFromProto(KPK::StringLiteralConvertible, "String", [&](Builder &builder) {
addFromProto(LK::StringLiteral, "String", [&](Builder &builder) {
builder.addTextChunk("\"");
builder.addSimpleNamedParameter("text");
builder.addTextChunk("\"");
});
addFromProto(KPK::ArrayLiteralConvertible, "Array", [&](Builder &builder) {
addFromProto(LK::ArrayLiteral, "Array", [&](Builder &builder) {
builder.addLeftBracket();
builder.addSimpleNamedParameter("item");
builder.addRightBracket();
});
addFromProto(KPK::DictionaryLiteralConvertible, "Dictionary", [&](Builder &builder) {
addFromProto(LK::DictionaryLiteral, "Dictionary", [&](Builder &builder) {
builder.addLeftBracket();
builder.addSimpleNamedParameter("key");
builder.addTextChunk(": ");
Expand All @@ -2720,7 +2781,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
});

auto floatType = context.getFloatDecl()->getDeclaredType();
addFromProto(KPK::_ColorLiteralConvertible, "", [&](Builder &builder) {
addFromProto(LK::_ColorLiteral, "", [&](Builder &builder) {
builder.addLeftBracket();
builder.addTextChunk("#Color");
builder.addLeftParen();
Expand All @@ -2741,8 +2802,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

// Add tuple completion (item, item).
{
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Pattern,
CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal,
SemanticContextKind::None, {});
builder.setLiteralKind(LK::Tuple);

builder.addLeftParen();
builder.addSimpleNamedParameter("item");
builder.addComma();
Expand Down Expand Up @@ -3662,6 +3725,7 @@ static void addStmtKeywords(CodeCompletionResultSink &Sink) {
AddKeyword("__DSO_HANDLE__", "UnsafeMutablePointer<Void>");
}


void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink) {
switch (Kind) {
case CompletionKind::None:
Expand Down
3 changes: 3 additions & 0 deletions lib/IDE/CodeCompletionResultBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CodeCompletionResultBuilder {
SemanticContextKind SemanticContext;
unsigned NumBytesToErase = 0;
const Decl *AssociatedDecl = nullptr;
Optional<CodeCompletionLiteralKind> LiteralKind;
unsigned CurrentNestingLevel = 0;
SmallVector<CodeCompletionString::Chunk, 4> Chunks;
llvm::PointerUnion<const ModuleDecl *, const clang::Module *>
Expand Down Expand Up @@ -87,6 +88,8 @@ class CodeCompletionResultBuilder {

void setAssociatedDecl(const Decl *D);

void setLiteralKind(CodeCompletionLiteralKind kind) { LiteralKind = kind; }

void
setExpectedTypeRelation(CodeCompletionResult::ExpectedTypeRelation relation) {
ExpectedTypeRelation = relation;
Expand Down
7 changes: 4 additions & 3 deletions test/IDE/complete_at_start_1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// rdar://14585108
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=A | FileCheck %s -check-prefix=A
// A: Begin completions
// A-DAG: Keyword/None: true[#Bool#]{{; name=.+$}}
// A-DAG: Keyword/None: false[#Bool#]{{; name=.+$}}
// A-DAG: Keyword/None: nil{{; name=.+$}}
// A-DAG: Keyword/None: func{{; name=.+$}}
// A-DAG: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
// A-DAG: Literal[Boolean]/None: false[#Bool#]{{; name=.+$}}
// A-DAG: Literal[Nil]/None: nil{{; name=.+$}}
// A-DAG: Decl[Struct]/OtherModule[Swift]: Int8[#Int8#]{{; name=.+$}}
// A-DAG: Decl[Struct]/OtherModule[Swift]: Int16[#Int16#]{{; name=.+$}}
// A-DAG: Decl[Struct]/OtherModule[Swift]: Int32[#Int32#]{{; name=.+$}}
Expand Down
7 changes: 4 additions & 3 deletions test/IDE/complete_expr_postfix_begin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ typealias FooTypealias = Int
// COMMON-DAG: Decl[Protocol]/CurrModule: FooProtocol[#FooProtocol#]{{; name=.+$}}
// COMMON-DAG: Decl[TypeAlias]/CurrModule: FooTypealias[#Int#]{{; name=.+$}}
// COMMON-DAG: Decl[GlobalVar]/CurrModule: fooObject[#FooStruct#]{{; name=.+$}}
// COMMON-DAG: Keyword/None: true[#Bool#]{{; name=.+$}}
// COMMON-DAG: Keyword/None: false[#Bool#]{{; name=.+$}}
// COMMON-DAG: Keyword/None: nil{{; name=.+$}}
// COMMON-DAG: Keyword/None: try{{; name=.+$}}
// COMMON-DAG: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
// COMMON-DAG: Literal[Boolean]/None: false[#Bool#]{{; name=.+$}}
// COMMON-DAG: Literal[Nil]/None: nil{{; name=.+$}}
// COMMON-DAG: Decl[Struct]/OtherModule[Swift]: Int8[#Int8#]{{; name=.+$}}
// COMMON-DAG: Decl[Struct]/OtherModule[Swift]: Int16[#Int16#]{{; name=.+$}}
// COMMON-DAG: Decl[Struct]/OtherModule[Swift]: Int32[#Int32#]{{; name=.+$}}
Expand Down
9 changes: 6 additions & 3 deletions test/IDE/complete_keywords.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,12 @@
// KW_DECL_STMT-DAG: Keyword/None: __FILE__[#String#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: __LINE__[#Int#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: __COLUMN__[#Int#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: false[#Bool#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: true[#Bool#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Keyword/None: nil{{; name=.+$}}
//
// Literals
//
// KW_DECL_STMT-DAG: Literal[Boolean]/None: false[#Bool#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
// KW_DECL_STMT-DAG: Literal[Nil]/None: nil{{; name=.+$}}
// KW_DECL_STMT: End completions

#^TOP_LEVEL_1^#
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/complete_multiple_files.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func topLevel1() {
}
// TOP_LEVEL_1: Begin completions
// TOP_LEVEL_1-NOT: ERROR
// TOP_LEVEL_1: Keyword/None: true[#Bool#]{{; name=.+$}}
// TOP_LEVEL_1: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
// TOP_LEVEL_1-NOT: true
// TOP_LEVEL_1-NOT: ERROR
// TOP_LEVEL_1: End completions
Expand Down
4 changes: 2 additions & 2 deletions test/IDE/complete_stmt_controlling_expr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ func testSwitchCaseWhereExprIJ1(fooObject: FooStruct) {
}

// COND_COMMON: Begin completions
// COND_COMMON-DAG: Keyword/None: true[#Bool#]{{; name=.+$}}
// COND_COMMON-DAG: Keyword/None: false[#Bool#]{{; name=.+$}}
// COND_COMMON-DAG: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
// COND_COMMON-DAG: Literal[Boolean]/None: false[#Bool#]{{; name=.+$}}
// COND_COMMON-DAG: Decl[LocalVar]/Local: fooObject[#FooStruct#]{{; name=.+$}}
// COND_COMMON-DAG: Decl[LocalVar]/Local: localInt[#Int#]{{; name=.+$}}
// COND_COMMON-DAG: Decl[LocalVar]/Local: localFooObject[#FooStruct#]{{; name=.+$}}
Expand Down
Loading

0 comments on commit 54a28a4

Please sign in to comment.