Skip to content

Commit 7eaed61

Browse files
committed
[CodeCompletion] Fix completion after unspaced binary operator
We were miscalculating 'isRightBound' when the RHS was a code-completion token leading to missing completions in unspaced binary expressions 1+<here> 1...<here> rdar://problem/24278699
1 parent c2f3ec1 commit 7eaed61

File tree

3 files changed

+25
-9
lines changed

3 files changed

+25
-9
lines changed

lib/Parse/Lexer.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -594,14 +594,21 @@ static bool isLeftBound(const char *tokBegin, const char *bufferBegin) {
594594

595595
/// Is the operator ending at the given character (actually one past the end)
596596
/// "right-bound"?
597-
static bool isRightBound(const char *tokEnd, bool isLeftBound) {
597+
///
598+
/// The code-completion point is considered right-bound.
599+
static bool isRightBound(const char *tokEnd, bool isLeftBound,
600+
const char *codeCompletionPtr) {
598601
switch (*tokEnd) {
599602
case ' ': case '\r': case '\n': case '\t': // whitespace
600603
case ')': case ']': case '}': // closing delimiters
601604
case ',': case ';': case ':': // expression separators
602-
case '\0': // whitespace / last char in file
603605
return false;
604606

607+
case '\0':
608+
if (tokEnd == codeCompletionPtr) // code-completion
609+
return true;
610+
return false; // whitespace / last char in file
611+
605612
case '.':
606613
// Prefer the '^' in "x^.y" to be a postfix op, not binary, but the '^' in
607614
// "^.y" to be a prefix op, not binary.
@@ -637,7 +644,7 @@ void Lexer::lexOperatorIdentifier() {
637644
// It's binary if either both sides are bound or both sides are not bound.
638645
// Otherwise, it's postfix if left-bound and prefix if right-bound.
639646
bool leftBound = isLeftBound(TokStart, BufferStart);
640-
bool rightBound = isRightBound(CurPtr, leftBound);
647+
bool rightBound = isRightBound(CurPtr, leftBound, CodeCompletionPtr);
641648

642649
// Match various reserved words.
643650
if (CurPtr-TokStart == 1) {
@@ -669,17 +676,16 @@ void Lexer::lexOperatorIdentifier() {
669676
const char *AfterHorzWhitespace = CurPtr;
670677
while (*AfterHorzWhitespace == ' ' || *AfterHorzWhitespace == '\t')
671678
++AfterHorzWhitespace;
672-
673-
// First, when we are code completing "x.<ESC>", then make sure to return
679+
680+
// First, when we are code completing "x. <ESC>", then make sure to return
674681
// a tok::period, since that is what the user is wanting to know about.
675-
// FIXME: isRightBound should consider this to be right bound.
676682
if (*AfterHorzWhitespace == '\0' &&
677683
AfterHorzWhitespace == CodeCompletionPtr) {
678684
diagnose(TokStart, diag::expected_member_name);
679685
return formToken(tok::period, TokStart);
680686
}
681-
682-
if (isRightBound(AfterHorzWhitespace, leftBound) &&
687+
688+
if (isRightBound(AfterHorzWhitespace, leftBound, CodeCompletionPtr) &&
683689
// Don't consider comments to be this. A leading slash is probably
684690
// either // or /* and most likely occurs just in our testsuite for
685691
// expected-error lines.

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,8 @@ static void parseGuardedPattern(Parser &P, GuardedPattern &result,
888888
}
889889
}
890890
if (parsingContext == GuardedPatternContext::Case &&
891-
P.Tok.is(tok::period) && P.peekToken().is(tok::code_complete)) {
891+
P.Tok.isAny(tok::period_prefix, tok::period) &&
892+
P.peekToken().is(tok::code_complete)) {
892893
setErrorResult();
893894
if (P.CodeCompletion) {
894895
P.consumeToken();

test/IDE/complete_expr_postfix_begin.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_2 | FileCheck %s -check-prefix=COMMON
33
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_3 | FileCheck %s -check-prefix=COMMON
44
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_4 | FileCheck %s -check-prefix=COMMON
5+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_5 | FileCheck %s -check-prefix=COMMON
6+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_6 | FileCheck %s -check-prefix=COMMON
57

68
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_IGNORED_1 | FileCheck %s -check-prefix=COMMON
79
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EXPR_POSTFIX_BEGIN_IGNORED_2 | FileCheck %s -check-prefix=COMMON
@@ -125,6 +127,13 @@ func testExprPostfixBegin4(fooParam: FooStruct) {
125127
"\(#^EXPR_POSTFIX_BEGIN_4^#)"
126128
}
127129

130+
func testExprPostfixBegin3(fooParam: FooStruct) {
131+
1+#^EXPR_POSTFIX_BEGIN_5^#
132+
}
133+
func testExprPostfixBegin3(fooParam: FooStruct) {
134+
for i in 1...#^EXPR_POSTFIX_BEGIN_6^#
135+
}
136+
128137
//===--- Test that we sometimes ignore the expr-postfix.
129138
// In these cases, displaying '.instance*' completion results is technically
130139
// valid, but would be extremely surprising.

0 commit comments

Comments
 (0)