Skip to content

Commit fce2615

Browse files
author
git apple-llvm automerger
committed
Merge commit '1eaa5da52feb' from swift/swift-5.2-branch into swift/master
2 parents ff71836 + 1eaa5da commit fce2615

File tree

8 files changed

+76
-54
lines changed

8 files changed

+76
-54
lines changed

lldb/include/lldb/Expression/REPL.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ class REPL : public IOHandlerDelegate {
130130
lldb::ValueObjectSP &valobj_sp,
131131
ExpressionVariable *var = nullptr) = 0;
132132

133-
virtual int CompleteCode(const std::string &current_code,
134-
StringList &matches) = 0;
133+
virtual void CompleteCode(const std::string &current_code,
134+
CompletionRequest &request) = 0;
135135

136136
OptionGroupFormat m_format_options = OptionGroupFormat(lldb::eFormatDefault);
137137
OptionGroupValueObjectDisplay m_varobj_options;

lldb/include/lldb/Utility/CompletionRequest.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class CompletionRequest {
104104

105105
llvm::StringRef GetRawLine() const { return m_command; }
106106
llvm::StringRef GetRawLineUntilCursor() const {
107-
return m_command.substr(0, m_cursor_index);
107+
return m_command.substr(0, m_raw_cursor_pos);
108108
}
109109

110110
unsigned GetRawCursorPos() const { return m_raw_cursor_pos; }
Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,42 @@
1-
from __future__ import print_function
2-
import pexpect
3-
import os
1+
42
import lldb
53
from lldbsuite.test.decorators import *
64
from lldbsuite.test.lldbtest import *
7-
from lldbsuite.test import lldbutil
5+
from lldbsuite.test.lldbpexpect import PExpectTest
86

7+
class SwiftCompletionTest(PExpectTest):
98

10-
class TestSwiftREPLCompletion(TestBase):
119
mydir = TestBase.compute_mydir(__file__)
1210

11+
# PExpect uses many timeouts internally and doesn't play well
12+
# under ASAN on a loaded machine..
13+
@skipIfAsan
1314
@skipUnlessDarwin
14-
def test_repl_completion(self):
15-
prompt = "Welcome to"
16-
child = pexpect.spawn('%s --repl' % (lldbtest_config.lldbExec))
17-
# Assign to make sure the sessions are killed during teardown
18-
self.child = child
19-
# Send a <TAB> and make sure we don't crash.
20-
child.sendline("import Foundatio\t")
21-
child.sendline("print(NSString(\"patatino\"))")
22-
child.expect("patatino")
15+
def test_basic_completion(self):
16+
17+
self.launch(extra_args=["--repl"], executable=None, dimensions=(100,500))
18+
19+
# Wait on the first prompt
20+
self.child.expect_exact("1>")
21+
# Press tab a few times which should do nothing.
22+
# Note that we don't get any indentation whitespace as
23+
# pexpect is not recognized as a interactive terminal by pexpect it seems.
24+
self.child.send("\t\t\t")
25+
26+
# Try completing something that only has one result "Hasabl" -> "Hashable".
27+
self.child.send("Hashabl\t")
28+
self.child.expect_exact("Hashable")
29+
self.child.sendline("")
30+
31+
# Try completing something that has multiple completions.
32+
self.child.send("Hash\t")
33+
self.child.expect_exact("Available completions:")
34+
self.child.expect_exact("Hashable")
35+
self.child.expect_exact("Hasher")
36+
self.child.sendline("")
37+
38+
def setUpCommands(self):
39+
return [] # REPL doesn't take any setup commands.
40+
41+
def expect_prompt(self):
42+
pass # No constant prompt on the REPL.

lldb/packages/Python/lldbsuite/test/lldbpexpect.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import absolute_import
33

44
# System modules
5+
import os
56
import sys
67

78
# Third-party modules
@@ -30,16 +31,21 @@ def expect_prompt(self):
3031
def launch(self, executable=None, extra_args=None, timeout=30, dimensions=None):
3132
logfile = getattr(sys.stdout, 'buffer',
3233
sys.stdout) if self.TraceOn() else None
34+
3335
args = ['--no-lldbinit', '--no-use-colors']
3436
for cmd in self.setUpCommands():
3537
args += ['-O', cmd]
3638
if executable is not None:
3739
args += ['--file', executable]
3840
if extra_args is not None:
3941
args.extend(extra_args)
42+
43+
env = dict(os.environ)
44+
env["TERM"]="vt100"
45+
4046
self.child = pexpect.spawn(
4147
lldbtest_config.lldbExec, args=args, logfile=logfile,
42-
timeout=timeout, dimensions=dimensions)
48+
timeout=timeout, dimensions=dimensions, env=env)
4349
self.expect_prompt()
4450
for cmd in self.setUpCommands():
4551
self.child.expect_exact(cmd)

lldb/source/Expression/REPL.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -501,14 +501,7 @@ void REPL::IOHandlerComplete(IOHandler &io_handler,
501501
current_code.append("\n");
502502
current_code += request.GetRawLineUntilCursor();
503503

504-
StringList matches;
505-
int result = CompleteCode(current_code, matches);
506-
if (result == -2) {
507-
assert(matches.GetSize() == 1);
508-
request.AddCompletion(matches.GetStringAtIndex(0), "",
509-
CompletionMode::RewriteLine);
510-
} else
511-
request.AddCompletions(matches);
504+
CompleteCode(current_code, request);
512505
}
513506

514507
bool QuitCommandOverrideCallback(void *baton, const char **argv) {

lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,8 @@ bool SwiftREPL::PrintOneVariable(Debugger &debugger, StreamFileSP &output_sp,
533533
return handled;
534534
}
535535

536-
int SwiftREPL::CompleteCode(const std::string &current_code,
537-
lldb_private::StringList &matches) {
536+
void SwiftREPL::CompleteCode(const std::string &current_code,
537+
CompletionRequest &request) {
538538
//----------------------------------------------------------------------g
539539
// If we use the target's SwiftASTContext for completion, it reaaallly
540540
// slows down subsequent expressions. The compiler team doesn't have time
@@ -546,7 +546,7 @@ int SwiftREPL::CompleteCode(const std::string &current_code,
546546
auto type_system_or_err = m_target.GetScratchTypeSystemForLanguage(eLanguageTypeSwift);
547547
if (!type_system_or_err) {
548548
llvm::consumeError(type_system_or_err.takeError());
549-
return 0;
549+
return;
550550
}
551551

552552
auto *target_swift_ast =
@@ -579,54 +579,56 @@ int SwiftREPL::CompleteCode(const std::string &current_code,
579579
swift::SourceFile &repl_source_file =
580580
repl_module->getMainSourceFile(swift::SourceFileKind::REPL);
581581

582+
// Swift likes to give us strings to append to the current token but
583+
// the CompletionRequest requires a replacement for the full current
584+
// token. Fix this by getting the current token here and we attach
585+
// the suffix we get from Swift.
586+
std::string prefix = request.GetCursorArgumentPrefix();
582587
llvm::StringRef current_code_ref(current_code);
583588
completions.populate(repl_source_file, current_code_ref);
589+
590+
// The root is the unique completion we need to use, so let's add it
591+
// to the completion list. As the completion is unique we can stop here.
584592
llvm::StringRef root = completions.getRoot();
585593
if (!root.empty()) {
586-
matches.AppendString(root.data(), root.size());
587-
return 1;
594+
request.AddCompletion(prefix + root.str(), "", CompletionMode::Partial);
595+
return;
588596
}
597+
589598
// Otherwise, advance through the completion state machine.
590599
const swift::CompletionState completion_state = completions.getState();
591600
switch (completion_state) {
592601
case swift::CompletionState::CompletedRoot: {
593-
// We completed the root. Next step is to display the completion list.
594-
matches.AppendString(""); // Empty string to indicate no completion,
595-
// just display other strings that come after it
602+
// Display the completion list.
596603
llvm::ArrayRef<llvm::StringRef> llvm_matches =
597604
completions.getCompletionList();
598605
for (const auto &llvm_match : llvm_matches) {
606+
// The completions here aren't really useful for actually completing
607+
// the token but are more descriptive hints for the user
608+
// (e.g. "isMultiple(of: Int) -> Bool"). They aren't useful for
609+
// actually completing anything so let's use the current token as
610+
// a placeholder that is always valid.
599611
if (!llvm_match.empty())
600-
matches.AppendString(llvm_match.data(), llvm_match.size());
612+
request.AddCompletion(prefix, llvm_match);
601613
}
602-
// Don't include the empty string we appended above or we will display
603-
// one
604-
// too many we need to return the magical value of one less than our
605-
// actual matches.
606-
// TODO: modify all IOHandlerDelegate::IOHandlerComplete() to use a
607-
// CompletionMatches
608-
// class that wraps up the "StringList matches;" along with other smarts
609-
// so we don't
610-
// have to return magic values and incorrect sizes.
611-
return matches.GetSize() - 1;
612614
} break;
613615

614616
case swift::CompletionState::DisplayedCompletionList: {
615617
// Complete the next completion stem in the cycle.
616-
llvm::StringRef stem = completions.getPreviousStem().InsertableString;
617-
matches.AppendString(stem.data(), stem.size());
618+
request.AddCompletion(prefix + completions.getPreviousStem().InsertableString.str());
618619
} break;
619620

620621
case swift::CompletionState::Empty:
621-
case swift::CompletionState::Unique:
622-
// We already provided a definitive completion--nothing else to do.
623-
break;
622+
case swift::CompletionState::Unique: {
623+
llvm::StringRef root = completions.getRoot();
624+
625+
if (!root.empty())
626+
request.AddCompletion(prefix + root.str());
627+
} break;
624628

625629
case swift::CompletionState::Invalid:
626630
llvm_unreachable("got an invalid completion set?!");
627631
}
628632
}
629633
}
630-
631-
return matches.GetSize();
632634
}

lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ class SwiftREPL : public REPL {
6868
lldb::ValueObjectSP &valobj_sp,
6969
ExpressionVariable *var = nullptr) override;
7070

71-
int CompleteCode(const std::string &current_code,
72-
StringList &matches) override;
71+
void CompleteCode(const std::string &current_code,
72+
CompletionRequest &request) override;
7373

7474
public:
7575
static bool classof(const REPL *repl) {

lldb/unittests/Utility/CompletionRequestTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ TEST(CompletionRequest, Constructor) {
2626
EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
2727
EXPECT_EQ(request.GetCursorIndex(), arg_index);
2828
EXPECT_EQ(request.GetCursorCharPosition(), arg_cursor_pos);
29+
EXPECT_EQ(request.GetRawLineUntilCursor(), "a b");
2930

3031
EXPECT_EQ(request.GetPartialParsedLine().GetArgumentCount(), 2u);
3132
EXPECT_STREQ(request.GetPartialParsedLine().GetArgumentAtIndex(1), "b");

0 commit comments

Comments
 (0)