Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions lldb/include/lldb/Utility/CompletionRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ class CompletionRequest {
CompletionRequest(llvm::StringRef command_line, unsigned raw_cursor_pos,
CompletionResult &result);

/// Sets the maximum number of completions that should be returned.
void SetMaxReturnElements(size_t max_return_elements) {
m_max_return_elements = max_return_elements;
}

/// Returns the raw user input used to create this CompletionRequest cut off
/// at the cursor position. The cursor will be at the end of the raw line.
llvm::StringRef GetRawLine() const {
Expand Down Expand Up @@ -157,6 +162,23 @@ class CompletionRequest {

size_t GetCursorIndex() const { return m_cursor_index; }

size_t GetMaxReturnElements() const { return m_max_return_elements; }

/// Returns true if the maximum number of completions has not been reached
/// yet, hence we should keep adding completions.
bool ShouldAddCompletions() const {
return GetMaxNumberOfCompletionsToAdd() > 0;
}

/// Returns the maximum number of completions that need to be added
/// until reaching the maximum
size_t GetMaxNumberOfCompletionsToAdd() const {
const size_t number_of_results = m_result.GetNumberOfResults();
if (number_of_results >= m_max_return_elements)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just call ShouldAddCompletions() and return 0 if false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But still it needs to return the number of completions if ShouldAddCompletions is true

I Changed ShouldAddCompletions to return GetMaxNumberOfCompletionsToAdd > 0 instead in order to reuse code

return 0;
return m_max_return_elements - number_of_results;
}

/// Adds a possible completion string. If the completion was already
/// suggested before, it will not be added to the list of results. A copy of
/// the suggested completion is stored, so the given string can be free'd
Expand Down Expand Up @@ -231,6 +253,8 @@ class CompletionRequest {
size_t m_cursor_index;
/// The cursor position in the argument indexed by m_cursor_index.
size_t m_cursor_char_position;
/// The maximum number of completions that should be returned.
size_t m_max_return_elements = std::numeric_limits<size_t>::max();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a sensible (non size_t max) default?


/// The result this request is supposed to fill out.
/// We keep this object private to ensure that no backend can in any way
Expand Down
4 changes: 2 additions & 2 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2257,12 +2257,12 @@ def complete_from_to(self, str_input, patterns):
substrs=[p],
)

def completions_match(self, command, completions):
def completions_match(self, command, completions, max_completions=-1):
"""Checks that the completions for the given command are equal to the
given list of completions"""
interp = self.dbg.GetCommandInterpreter()
match_strings = lldb.SBStringList()
interp.HandleCompletion(command, len(command), 0, -1, match_strings)
interp.HandleCompletion(command, len(command), 0, max_completions, match_strings)
# match_strings is a 1-indexed list, so we have to slice...
self.assertCountEqual(
completions, list(match_strings)[1:], "List of returned completion is wrong"
Expand Down
15 changes: 14 additions & 1 deletion lldb/source/API/SBCommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,26 @@ int SBCommandInterpreter::HandleCompletionWithDescriptions(
if (!IsValid())
return 0;

if (max_return_elements == 0)
return 0;

lldb_private::StringList lldb_matches, lldb_descriptions;
CompletionResult result;
CompletionRequest request(current_line, cursor - current_line, result);
if (max_return_elements > 0)
request.SetMaxReturnElements(max_return_elements);
m_opaque_ptr->HandleCompletion(request);
result.GetMatches(lldb_matches);
result.GetDescriptions(lldb_descriptions);

// limit the matches to the max_return_elements if necessary
if (max_return_elements > 0 &&
lldb_matches.GetSize() > static_cast<size_t>(max_return_elements)) {
lldb_matches.SetSize(max_return_elements);
lldb_descriptions.SetSize(max_return_elements);
}
int number_of_matches = lldb_matches.GetSize();

// Make the result array indexed from 1 again by adding the 'common prefix'
// of all completions as element 0. This is done to emulate the old API.
if (request.GetParsedLine().GetArgumentCount() == 0) {
Expand Down Expand Up @@ -303,7 +316,7 @@ int SBCommandInterpreter::HandleCompletionWithDescriptions(
matches.AppendList(temp_matches_list);
SBStringList temp_descriptions_list(&lldb_descriptions);
descriptions.AppendList(temp_descriptions_list);
return result.GetNumberOfResults();
return number_of_matches;
}

int SBCommandInterpreter::HandleCompletionWithDescriptions(
Expand Down
19 changes: 14 additions & 5 deletions lldb/source/Commands/CommandCompletions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks(
nullptr} // This one has to be last in the list.
};

for (int i = 0;; i++) {
for (int i = 0; request.ShouldAddCompletions(); i++) {
if (common_completions[i].type == lldb::eTerminatorCompletion)
break;
else if ((common_completions[i].type & completion_mask) ==
Expand Down Expand Up @@ -167,7 +167,9 @@ class SourceFileCompleter : public Completer {
m_matching_files.AppendIfUnique(context.comp_unit->GetPrimaryFile());
}
}
return Searcher::eCallbackReturnContinue;
return m_matching_files.GetSize() >= m_request.GetMaxNumberOfCompletionsToAdd()
? Searcher::eCallbackReturnStop
: Searcher::eCallbackReturnContinue;
}

void DoCompletion(SearchFilter *filter) override {
Expand Down Expand Up @@ -230,6 +232,9 @@ class SymbolCompleter : public Completer {

// Now add the functions & symbols to the list - only add if unique:
for (const SymbolContext &sc : sc_list) {
if (m_match_set.size() >= m_request.GetMaxNumberOfCompletionsToAdd())
break;

ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
// Ensure that the function name matches the regex. This is more than
// a sanity check. It is possible that the demangled function name
Expand All @@ -239,7 +244,9 @@ class SymbolCompleter : public Completer {
m_match_set.insert(func_name);
}
}
return Searcher::eCallbackReturnContinue;
return m_match_set.size() >= m_request.GetMaxNumberOfCompletionsToAdd()
? Searcher::eCallbackReturnStop
: Searcher::eCallbackReturnContinue;
}

void DoCompletion(SearchFilter *filter) override {
Expand Down Expand Up @@ -305,7 +312,8 @@ class ModuleCompleter : public Completer {
m_request.AddCompletion(cur_file_name);
}
}
return Searcher::eCallbackReturnContinue;
return m_request.ShouldAddCompletions() ? Searcher::eCallbackReturnContinue
: Searcher::eCallbackReturnStop;
}

void DoCompletion(SearchFilter *filter) override { filter->Search(*this); }
Expand Down Expand Up @@ -429,7 +437,8 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
std::error_code EC;
llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC);
llvm::vfs::directory_iterator End;
for (; Iter != End && !EC; Iter.increment(EC)) {
for (; Iter != End && !EC && request.ShouldAddCompletions();
Iter.increment(EC)) {
auto &Entry = *Iter;
llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,37 @@ def test_expr_completion_with_descriptions(self):
enforce_order=True,
)

def test_expr_completion_max_results(self):
self.build()
self.main_source = "main.cpp"
self.main_source_spec = lldb.SBFileSpec(self.main_source)
self.createTestTarget()

(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "// Break here", self.main_source_spec
)

expected_completions = [
"some_expr.~Expr()",
"some_expr.operator=(", # Copy operator
"some_expr.operator=(", # Move operator
"some_expr.MemberVariableBar",
"some_expr.StaticMemberMethodBar()",
"some_expr.Self()",
"some_expr.FooNoArgsBar()",
"some_expr.FooWithArgsBar(",
"some_expr.FooNumbersBar1()",
"some_expr.FooUnderscoreBar_()",
"some_expr.FooWithMultipleArgsBar(",
]

for i in range(1, len(expected_completions)):
self.completions_match(
"expr some_expr.",
expected_completions[:i],
max_completions=i,
)

def assume_no_completions(self, str_input, cursor_pos=None):
interp = self.dbg.GetCommandInterpreter()
match_strings = lldb.SBStringList()
Expand Down