Skip to content

[lldb] Print hint if object description is requested but not implemented #7140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
2 changes: 2 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,

llvm::StringRef GetAutosuggestionAnsiSuffix() const;

bool GetShowDontUsePoHint() const;

bool GetUseSourceCache() const;

bool SetUseSourceCache(bool use_source_cache);
Expand Down
56 changes: 53 additions & 3 deletions lldb/source/Commands/CommandObjectDWIMPrint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"

#include <regex>

using namespace llvm;
using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -109,6 +111,37 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
language = frame->GuessLanguage();
// END SWIFT

// Add a hint if object description was requested, but no description
// function was implemented.
auto maybe_add_hint = [&](llvm::StringRef output) {
// Identify the default output of object description for Swift and
// Objective-C
// "<Name: 0x...>. The regex is:
// - Start with "<".
// - Followed by 1 or more non-whitespace characters.
// - Followed by ": 0x".
// - Followed by 5 or more hex digits.
// - Followed by ">".
// - End with zero or more whitespace characters.
const std::regex swift_class_regex("^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");

if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&
(language == lldb::eLanguageTypeSwift ||
language == lldb::eLanguageTypeObjC) &&
std::regex_match(output.data(), swift_class_regex)) {

static bool note_shown = false;
if (note_shown)
return;

result.GetOutputStream()
<< "note: object description requested, but type doesn't implement "
"a custom object description. Consider using \"p\" instead of "
"\"po\" (this note will only be shown once per debug session).\n";
note_shown = true;
}
};

// First, try `expr` as the name of a frame variable.
if (frame) {
auto valobj_sp = frame->FindVariable(ConstString(expr));
Expand All @@ -126,7 +159,15 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
flags, expr);
}

valobj_sp->Dump(result.GetOutputStream(), dump_options);
if (is_po) {
StreamString temp_result_stream;
valobj_sp->Dump(temp_result_stream, dump_options);
llvm::StringRef output = temp_result_stream.GetString();
maybe_add_hint(output);
result.GetOutputStream() << output;
} else {
valobj_sp->Dump(result.GetOutputStream(), dump_options);
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
Expand Down Expand Up @@ -185,8 +226,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
expr);
}

if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
valobj_sp->Dump(result.GetOutputStream(), dump_options);
if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) {
if (is_po) {
StreamString temp_result_stream;
valobj_sp->Dump(temp_result_stream, dump_options);
llvm::StringRef output = temp_result_stream.GetString();
maybe_add_hint(output);
result.GetOutputStream() << output;
} else {
valobj_sp->Dump(result.GetOutputStream(), dump_options);
}
}

if (suppress_result)
if (auto result_var_sp =
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Core/CoreProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ let Definition = "debugger" in {
Global,
DefaultStringValue<"${ansi.normal}">,
Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
def ShowDontUsePoHint: Property<"show-dont-use-po-hint", "Boolean">,
Global,
DefaultTrue,
Desc<"If true, and object description was requested for a type that does not implement it, LLDB will print a hint telling the user to consider using p instead.">;
def DWIMPrintVerbosity: Property<"dwim-print-verbosity", "Enum">,
Global,
DefaultEnumValue<"eDWIMPrintVerbosityNone">,
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,12 @@ llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
}

bool Debugger::GetShowDontUsePoHint() const {
const uint32_t idx = ePropertyShowDontUsePoHint;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr,
idx, g_debugger_properties[idx].default_uint_value != 0);
}

bool Debugger::GetUseSourceCache() const {
const uint32_t idx = ePropertyUseSourceCache;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/lang/objc/objc-po-hint/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OBJC_SOURCES := main.m
LD_EXTRAS = -lobjc -framework Foundation

include Makefile.rules
49 changes: 49 additions & 0 deletions lldb/test/API/lang/objc/objc-po-hint/TestObjcPoHint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestObjcPoHint(TestBase):
NO_DEBUG_INFO_TESTCASE = True

def test_show_po_hint(self):
### Test that the po hint is shown once with the DWIM print command
self.build()
_, _, _, _ = lldbutil.run_to_source_breakpoint(
self, "Set breakpoint here", lldb.SBFileSpec("main.m")
)
# Make sure the hint is printed the first time
self.expect(
"dwim-print -O -- foo",
substrs=[
"note: object description requested, but type doesn't implement "
'a custom object description. Consider using "p" instead of "po"',
"<Foo: 0x",
],
)

# Make sure it's not printed again.
self.expect(
"dwim-print -O -- foo",
substrs=[
"note: object description"
],
matching=False,
)

def test_show_po_hint_disabled(self):
### Test that when the setting is disabled the hint is not printed
self.build()
_, _, _, _ = lldbutil.run_to_source_breakpoint(
self, "Set breakpoint here", lldb.SBFileSpec("main.m")
)
self.runCmd("setting set show-dont-use-po-hint false")
# Make sure the hint is printed the first time
self.expect(
"dwim-print -O -- foo",
substrs=[
"note: object description"
],
matching=False,
)
22 changes: 22 additions & 0 deletions lldb/test/API/lang/objc/objc-po-hint/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>

@interface Foo : NSObject {}

-(id) init;

@end

@implementation Foo

-(id) init
{
return self = [super init];
}
@end

int main()
{
Foo *foo = [Foo new];
NSLog(@"a"); // Set breakpoint here.
return 0;
}