Return a named error in the result object of an expression with no result

Before we returned an error that was not exposed in the SB API and no useful
error message.  This change returns eExpressionProducedNoResult and an
appropriate error string.

<rdar://problem/44539514>

Differential Revision: https://reviews.llvm.org/D53309

llvm-svn: 344647
This commit is contained in:
Jim Ingham 2018-10-16 21:58:40 +00:00
parent d33f6e73e1
commit b1ecc3cac2
10 changed files with 73 additions and 11 deletions

View File

@ -288,10 +288,6 @@ public:
uint32_t line_offset = 0, std::string *fixed_expression = nullptr,
lldb::ModuleSP *jit_module_sp_ptr = nullptr);
static const Status::ValueType kNoResult =
0x1001; ///< ValueObject::GetError() returns this if there is no result
/// from the expression.
const char *GetFixedText() {
if (m_fixed_text.empty())
return nullptr;

View File

@ -254,7 +254,8 @@ enum ExpressionResults {
eExpressionHitBreakpoint,
eExpressionTimedOut,
eExpressionResultUnavailable,
eExpressionStoppedForDebug
eExpressionStoppedForDebug,
eExpressionProducedNoResult
};
enum SearchDepth {

View File

@ -0,0 +1,6 @@
LEVEL = ../../make
C_SOURCES := main.c
CFLAGS_EXTRAS += -std=c99
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,45 @@
"""
Test that an expression that returns no result returns a sensible error.
"""
from __future__ import print_function
import os
import time
import re
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class TestExprNoResult(TestBase):
mydir = TestBase.compute_mydir(__file__)
# If your test case doesn't stress debug info, the
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True
def test_no_result(self):
"""Run an expression that has no result, check the error."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
self.sample_test()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
def sample_test(self):
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
"Set a breakpoint here", self.main_source_file)
frame = thread.GetFrameAtIndex(0)
result = frame.EvaluateExpression("int $x = 10")
# No result expressions are considered to fail:
self.assertTrue(result.GetError().Fail(), "An expression with no result is a failure.")
# But the reason should be eExpressionProducedNoResult
self.assertEqual(result.GetError().GetError(), lldb.eExpressionProducedNoResult,
"But the right kind of failure")

View File

@ -0,0 +1,9 @@
#include <stdio.h>
int
main()
{
int test_var = 10;
printf ("Set a breakpoint here: %d.\n", test_var);
return 0;
}

View File

@ -487,7 +487,7 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
}
} else {
if (result_valobj_sp->GetError().GetError() ==
UserExpression::kNoResult) {
lldb::eExpressionProducedNoResult) {
if (format != eFormatVoid &&
m_interpreter.GetDebugger().GetNotifyVoid()) {
error_stream->PutCString("(void)\n");

View File

@ -256,7 +256,7 @@ bool ExpressionSourceCode::GetText(std::string &text,
}
ConstString object_name;
if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) {
if (1 /* Language::LanguageIsCPlusPlus(frame->GetLanguage())*/) {
if (target->GetInjectLocalVariables(&exe_ctx)) {
lldb::VariableListSP var_list_sp =
frame->GetInScopeVariableList(false, true);

View File

@ -325,7 +325,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
if (result_valobj_sp->GetError().Success()) {
handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
} else if (result_valobj_sp->GetError().GetError() ==
UserExpression::kNoResult) {
lldb::eExpressionProducedNoResult) {
if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
error_sp->PutCString("(void)\n");
handled = true;

View File

@ -151,6 +151,9 @@ lldb::ExpressionResults UserExpression::Evaluate(
? UserExpression::eResultTypeId
: UserExpression::eResultTypeAny;
lldb::ExpressionResults execution_results = lldb::eExpressionSetupError;
static const char *no_result_error = "Expression completed successfully "
"but had no result";
Target *target = exe_ctx.GetTargetPtr();
if (!target) {
@ -304,7 +307,8 @@ lldb::ExpressionResults UserExpression::Evaluate(
error.SetExpressionError(lldb::eExpressionSetupError,
"expression needed to run but couldn't");
} else if (execution_policy == eExecutionPolicyTopLevel) {
error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric);
error.SetExpressionError(lldb::eExpressionProducedNoResult,
no_result_error);
return lldb::eExpressionCompleted;
} else {
if (options.InvokeCancelCallback(lldb::eExpressionEvaluationExecution)) {
@ -349,7 +353,8 @@ lldb::ExpressionResults UserExpression::Evaluate(
log->Printf("== [UserExpression::Evaluate] Execution completed "
"normally with no result ==");
error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric);
error.SetExpressionError(lldb::eExpressionProducedNoResult,
no_result_error);
}
}
}

View File

@ -1758,7 +1758,7 @@ bool RenderScriptRuntime::EvalRSExpression(const char *expr,
if (!expr_result->GetError().Success()) {
Status err = expr_result->GetError();
// Expression returned is void, so this is actually a success
if (err.GetError() == UserExpression::kNoResult) {
if (err.GetError() == lldb::eExpressionProducedNoResult) {
if (log)
log->Printf("%s - expression returned void.", __FUNCTION__);