Skip to content

Commit 0e18148

Browse files
committed
fix: Improve trimming of Swift function names
Some Swift for Windows function names were trimmed to incorrect tokens in the UI, resulting in hard-to-read stack traces. For instance, some functions were shown as "throws" and closures were shown as "#1". This change fixes the former issue by using the correct function name. Closures are now displayed as "closure in <function name>", and initialization expressions are displayed as "initializer expression of <value>", improving the user experience when browsing stack traces.
1 parent b5d447d commit 0e18148

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

src/sentry/stacktraces/functions.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -228,19 +228,40 @@ def process_generics(value, start):
228228
#
229229
# ["unsigned", "int", "whatever"] -> whatever
230230
# ["@objc", "whatever", "->", "int"] -> whatever
231-
try:
232-
func_token = tokens[tokens.index("⟿") - 1]
233-
except ValueError:
234-
if tokens:
231+
if function.find("initialization expression of") != -1:
232+
# Swift initializer expression.
233+
last_of_index = len(tokens) - 1 - tokens[::-1].index("of")
234+
func_token = tokens[last_of_index + 1]
235+
if func_token == "static":
236+
# Static initializer expression, the object is the next token.
237+
func_token = tokens[last_of_index + 2]
238+
if func_token.startswith(":"):
239+
# Trim the colon from the function name.
240+
func_token = func_token[1:]
241+
func_token = "initializer expression of " + func_token
242+
elif tokens:
243+
try:
244+
last_arrow_index = len(tokens) - 1 - tokens[::-1].index("⟿")
245+
func_token = tokens[last_arrow_index - 1]
246+
if func_token == "throws":
247+
# Throwing Swift function, the function name is the previous token.
248+
func_token = tokens[last_arrow_index - 2]
249+
except (ValueError, IndexError):
250+
# No arrow, use the last token.
251+
last_arrow_index = -1
235252
func_token = tokens[-1]
236-
else:
237-
func_token = None
253+
else:
254+
func_token = None
238255

239256
if func_token:
240257
if func_token.startswith("@") and platform in ("cocoa", "swift"):
241258
# Found a Swift attribute instead of a function name, must be an
242259
# anonymous function
243260
func_token = ("thunk for " if is_thunk else "") + "closure"
261+
elif "closure" in tokens:
262+
# Found a closure.
263+
func_token = "closure in " + func_token
264+
244265
function = (
245266
func_token.replace("⟨", "<")
246267
.replace("◯", "()")

tests/sentry/stacktraces/test_functions.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@
103103
],
104104
["pthread_cond_timedwait@@GLIBC_2.3.2", "pthread_cond_timedwait"],
105105
["glob64@GLIBC_2.2", "glob64"],
106+
[
107+
"static Namespace.ThrowingFunction() throws -> Namespace.ExitValue?",
108+
"Namespace.ThrowingFunction",
109+
],
110+
[
111+
"closure #1 @Swift.MainActor () -> () in static Foo.CallFunction(args: [Swift.String]) -> ()",
112+
"closure in Foo.CallFunction",
113+
],
114+
[
115+
"closure #1 () -> () in Bar.PostTask(() -> ()) -> ()",
116+
"closure in Bar.PostTask",
117+
],
118+
[
119+
"closure #1 @Sendable () -> Swift.String in variable initialization expression of static Namespace.Class.var : Namespace.Parent",
120+
"cl,osure in initializer expression of Namespace.Class.var",
121+
],
122+
[
123+
"variable initialization expression of static Namespace.Class.var : Namespace.Parent",
124+
"initializer expression of Namespace.Class.var",
125+
],
126+
[
127+
"closure #1 () -> () in variable initialization expression of static (extension in SpaceCreation):Namespace.Class.var : Namespace.Parent",
128+
"closure in initializer expression of Namespace.Class.var",
129+
],
106130
],
107131
)
108132
def test_trim_native_function_name(input, output):
@@ -142,14 +166,13 @@ def test_trim_csharp_function_name(input, output):
142166
"partial apply for thunk for @escaping @callee_guaranteed (@guaranteed SomeType, @guaranteed [String : SomeType2], @guaranteed SomeType3) -> ()",
143167
"thunk for closure",
144168
],
145-
[ # "closure ... in ..." functions are converted to containing
146-
# function. We might want to change this in the future
169+
[
147170
"closure #1 (T1) in foo(bar: T2)",
148-
"foo",
171+
"closure in foo",
149172
],
150173
[
151174
"partial apply for closure #1 () in closure #2 (T1) in f1(_: T2, arg: T3)",
152-
"f1",
175+
"closure in f1",
153176
],
154177
],
155178
)

0 commit comments

Comments
 (0)