diff --git a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py --- a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py +++ b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py @@ -576,3 +576,39 @@ ''' initCommands = ['settings set symbols.load-on-demand true'] self.darwin_dwarf_missing_obj(initCommands) + + + @skipIfWindows + @skipIfRemote + def test_return_value(self): + ''' + Test that local variables include a an entry for the return value + when stepping out of a function with a return value. + ''' + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + breakpoint4_line = line_number(source, "// breakpoint 4") + lines = [breakpoint4_line] + breakpoint_ids = self.set_source_breakpoints(source, lines) + self.assertEqual( + len(breakpoint_ids), len(lines), "expect correct number of breakpoints" + ) + self.continue_to_breakpoints(breakpoint_ids) + tid = self.vscode.get_thread_id() + + # We haven't stepped out of a function with a return value so there + # should be no variable named 'Return value'. + locals = self.vscode.get_local_variables() + names = [var['name'] for var in locals] + self.assertNotIn('Return value', names) + + self.stepOut(threadId=tid, waitForStop=True) + globals = self.vscode.get_local_variables() + global_names = [var['name'] for var in globals] + # The return value should only be included in the local scope. + self.assertNotIn('Return value', global_names) + return_value = self.get_local_as_int('Return value', threadId=tid) + self.assertEqual(return_value, 0, + 'verify "Return value" was set to 0 (0 != %i)' % (return_value)) + diff --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h --- a/lldb/tools/lldb-vscode/JSONUtils.h +++ b/lldb/tools/lldb-vscode/JSONUtils.h @@ -457,12 +457,17 @@ /// As VSCode doesn't render two of more variables with the same name, we /// apply a suffix to distinguish duplicated variables. /// +/// \param[in] name_override +/// A name to give the variable when a predetermined name is known. +/// Otherwise, the name is derived from the variable. +/// /// \return /// A "Variable" JSON object with that follows the formal JSON /// definition outlined by Microsoft. llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, int64_t varID, bool format_hex, - bool is_name_duplicated = false); + bool is_name_duplicated = false, + const char *name_override = nullptr); llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit); diff --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp --- a/lldb/tools/lldb-vscode/JSONUtils.cpp +++ b/lldb/tools/lldb-vscode/JSONUtils.cpp @@ -1034,10 +1034,13 @@ // } llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, int64_t varID, bool format_hex, - bool is_name_duplicated) { + bool is_name_duplicated, + const char *name_override) { llvm::json::Object object; - EmplaceSafeString(object, "name", - CreateUniqueVariableNameForDisplay(v, is_name_duplicated)); + auto name = name_override + ? name_override + : CreateUniqueVariableNameForDisplay(v, is_name_duplicated); + EmplaceSafeString(object, "name", name); if (format_hex) v.SetFormat(lldb::eFormatHex); diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -2960,6 +2960,19 @@ reg.SetFormat(lldb::eFormatAddressInfo); } } + } else if (variablesReference == VARREF_LOCALS) { + auto return_value = + g_vsc.target.GetProcess().GetSelectedThread().GetStopReturnValue(); + if (return_value.IsValid()) { + int64_t var_ref = 0; + if (return_value.MightHaveChildren()) { + var_ref = g_vsc.variables.InsertExpandableVariable( + return_value, /*is_permanent=*/false); + } + variables.emplace_back(CreateVariable( + return_value, var_ref, var_ref != 0 ? var_ref : UINT64_MAX, hex, + /*is_name_duplicated=*/false, "Return value")); + } } num_children = top_scope->GetSize();