Skip to content

[lldb] Support breakpoints on specific property accessor blocks #8546

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
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
19 changes: 19 additions & 0 deletions lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,25 @@ SwiftLanguage::GetMethodNameVariants(ConstString method_name) const {
if (method_name.GetMangledCounterpart(counterpart))
if (SwiftLanguageRuntime::IsSwiftMangledName(counterpart.GetStringRef()))
variant_names.emplace_back(counterpart, eFunctionNameTypeFull);

// Properties can have multiple accessor blocks. This section of code supports
// breakpoints on accessor blocks by name.

Choose a reason for hiding this comment

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

Is accessor "block" a term of art? I would have expected this to be called an "accessor method" or just an "accessor".

Copy link
Author

@kastiglione kastiglione Apr 5, 2024

Choose a reason for hiding this comment

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

the documentation of the swift grammar calls them blocks, see "variable-declaration" in https://docs.swift.org/swift-book/documentation/the-swift-programming-language/summaryofthegrammar#Declarations

I'm fine with removing the word block though.

//
// By default, the name `A.B` is treated as a fully qualified name, where `B`
// is the basename. However, some names can be interpreted in two ways, for
// example `A.get`. First, it can refer to the name `get` (in module `A`, or
// in type `A`). Second, it can refer the *getter* block for property `A`.
// LLDB's baseline behavior handles the first case. The second case is
// produced here as a variant name.
for (StringRef suffix : {".get", ".set", ".willset", ".didset"})
if (method_name.GetStringRef().ends_with(suffix)) {
// The method name, complete with suffix, *is* the variant.
variant_names.emplace_back(method_name, eFunctionNameTypeFull |
eFunctionNameTypeBase |
eFunctionNameTypeMethod);
break;
}

return variant_names;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

SWIFT_SOURCES := main.swift

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *


class TestCase(TestBase):
@swiftTest
def test(self):
"""Test that a breakpoint on a property accessor can be set by name."""
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
for name in (
"read_only.get",
"read_write.get",
"read_write.set",
"observed.willset",
"observed.didset",
):
bp = target.BreakpointCreateByName(name, "a.out")
self.assertEqual(bp.num_locations, 1, f"{name} breakpoint failed")

# Setting a breakpoint on the name "get" should not create a breakpoint
# matching property getters. The other accerssor suffixes should also
# not succeed as bare names.
for name in ("get", "set", "willset", "didset"):
bp = target.BreakpointCreateByName(name, "a.out")
self.assertEqual(bp.num_locations, 0, f"{name} breakpoint unexpected")
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
struct Thing {
var read_only: Int { 22 + 15 }

var read_write: Int {
get { 23 + 41 }
set { print("nothing") }
}

var observed: Int {
willSet { print("willSet") }
didSet { print("didSet") }
}
}