We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
native symbolicated 'const' functions incorrectly trimmed
### Environment

self-hosted (https://develop.sentry.dev/self-hosted/)

### Steps to Reproduce

Have the following verbose native frame `ShellCorona::screenInvariants() const [clone .cold] (shellcorona.cpp:847)`

The event has platform:native and the project has platform:native-qt in case that makes a difference

Full json blob of the frame:
```
            {
              "function": "const",
              "raw_function": "ShellCorona::screenInvariants() const [clone .cold]",
              "symbol": "_ZNK11ShellCorona16screenInvariantsEv.cold",
              "package": "/usr/bin/plasmashell",
              "filename": "shellcorona.cpp",
              "abs_path": "obj-x86_64-linux-gnu/shell/shell/shellcorona.cpp",
              "lineno": 847,
              "in_app": false,
              "vars": {},
              "data": {
                "orig_in_app": -1,
                "symbolicator_status": "symbolicated"
              },
              "instruction_addr": "0x558ba221ba82"
            },
```

### Expected Result

Trimmed name should be something like `ShellCorona::screenInvariants (shellcorona.cpp:847)`

### Actual Result

Trimmed name is `const (shellcorona.cpp:847)`

### Product Area

Issues

### Link

_No response_

### DSN

_No response_

### Version

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/sentry/stacktraces/functions.py`
Content:
```
1 from __future__ import annotations
2 
3 import re
4 from typing import Any
5 from urllib.parse import urlparse
6 
7 from django.core.exceptions import ValidationError
8 from django.core.validators import URLValidator
9 
10 from sentry.interfaces.stacktrace import Frame
11 from sentry.stacktraces.platform import get_behavior_family_for_platform
12 from sentry.utils.safe import setdefault_path
13 
14 _windecl_hash = re.compile(r"^@?(.*?)@[0-9]+$")
15 _rust_hash = re.compile(r"::h[a-z0-9]{16}$")
16 _gnu_version = re.compile(r"@@?GLIBC_([0-9.]+)$")
17 _cpp_trailer_re = re.compile(r"(\bconst\b|&)$")
18 _rust_blanket_re = re.compile(r"^([A-Z] as )")
19 _lambda_re = re.compile(
20     r"""(?x)
21     # gcc
22     (?:
23         \{
24             lambda\(.*?\)\#\d+
25         \}
26     ) |
27     # msvc
28     (?:
29         \blambda_[a-f0-9]{32}\b
30     ) |
31     # clang
32     (?:
33         \$_\d+\b
34     )
35     """
36 )
37 _anon_namespace_re = re.compile(
38     r"""(?x)
39     \?A0x[a-f0-9]{8}::
40     """
41 )
42 
43 
44 PAIRS = {"(": ")", "{": "}", "[": "]", "<": ">"}
45 
46 
47 def replace_enclosed_string(s, start, end, replacement=None):
48     if start not in s:
49         return s
50 
51     depth = 0
52 
53     rv = []
54     pair_start = None
55     for idx, char in enumerate(s):
56         if char == start:
57             if depth == 0:
58                 pair_start = idx
59             depth += 1
60         elif char == end:
61             depth -= 1
62             if depth == 0:
63                 if replacement is not None:
64                     if callable(replacement):
65                         rv.append(replacement(s[pair_start + 1 : idx], pair_start))
66                     else:
67                         rv.append(replacement)
68         elif depth == 0:
69             rv.append(char)
70 
71     return "".join(rv)
72 
73 
74 def split_func_tokens(s):
75     buf = []
76     rv = []
77     stack = []
78     end = 0
79 
80     for idx, char in enumerate(s):
81         if char in PAIRS:
82             stack.append(PAIRS[char])
83         elif stack and char == stack[-1]:
84             stack.pop()
85             if not stack:
86                 buf.append(s[end : idx + 1])
87                 end = idx + 1
88         elif not stack:
89             if char.isspace():
90                 if buf:
91                     rv.append(buf)
92                 buf = []
93             else:
94                 buf.append(s[end : idx + 1])
95             end = idx + 1
96 
97     if buf:
98         rv.append(buf)
99 
100     return ["".join(x) for x in rv]
101 
102 
103 def trim_function_name(function, platform, normalize_lambdas=True):
104     """Given a function value from the frame's function attribute this returns
105     a trimmed version that can be stored in `function_name`.  This is only used
106     if the client did not supply a value itself already.
107     """
108     if platform == "csharp":
109         return trim_csharp_function_name(function)
110     if get_behavior_family_for_platform(platform) == "native":
111         return trim_native_function_name(function, platform, normalize_lambdas=normalize_lambdas)
112     return function
113 
114 
115 def trim_csharp_function_name(function):
116     """This trims off signatures from C# frames.  This takes advantage of the
117     Unity not emitting any return values and using a space before the argument
118     list.
119 
120     Note that there is disagreement between Unity and the main .NET SDK about
121     the function names.  The Unity SDK emits the entire function with module
122     in the `function` name similar to native, the .NET SDK emits it in individual
123     parts of the frame.
124     """
125     return function.split(" (", 1)[0]
126 
127 
128 def trim_native_function_name(function, platform, normalize_lambdas=True):
129     if function in ("<redacted>", "<unknown>"):
130         return function
131 
132     original_function = function
133     function = function.strip()
134 
135     # Ensure we don't operate on objc functions
136     if function.startswith(("[", "+[", "-[")):
137         return function
138 
139     # Chop off C++ trailers
140     while True:
141         match = _cpp_trailer_re.search(function)
142         if match is None:
143             break
144         function = function[: match.start()].rstrip()
145 
146     # Because operator<< really screws with our balancing, so let's work
147     # around that by replacing it with a character we do not observe in
148     # `split_func_tokens` or `replace_enclosed_string`.
149     function = (
150         function.replace("operator<<", "operator⟨⟨")
151         .replace("operator<", "operator⟨")
152         .replace("operator()", "operator◯")
153         .replace("operator->", "operator⟿")
154         .replace(" -> ", " ⟿ ")
155         .replace("`anonymous namespace'", "〔anonymousnamespace〕")
156     )
157 
158     # normalize C++ lambdas.  This is necessary because different
159     # compilers use different rules for now to name a lambda and they are
160     # all quite inconsistent.  This does not give us perfect answers to
161     # this problem but closer.  In particular msvc will call a lambda
162     # something like `lambda_deadbeefeefffeeffeeff` whereas clang for
163     # instance will name it `main::$_0` which will tell us in which outer
164     # function it was declared.
165     if normalize_lambdas:
166         function = _lambda_re.sub("lambda", function)
167 
168     # Normalize MSVC anonymous namespaces from inline functions.  For inline
169     # functions, the compiler inconsistently renders anonymous namespaces with
170     # their hash.  For regular functions,  "`anonymous namespace'" is used.
171     # The regular expression matches the trailing "::" to avoid accidental
172     # replacement in mangled function names.
173     if normalize_lambdas:
174         function = _anon_namespace_re.sub("〔anonymousnamespace〕::", function)
175 
176     # Remove the arguments if there is one.
177     def process_args(value, start):
178         value = value.strip()
179         if value in ("anonymous namespace", "operator"):
180             return "(%s)" % value
181         return ""
182 
183     function = replace_enclosed_string(function, "(", ")", process_args)
184 
185     # Resolve generic types, but special case rust which uses things like
186     # <Foo as Bar>::baz to denote traits.
187     def process_generics(value, start):
188         # Special case for lambdas
189         if value == "lambda" or _lambda_re.match(value):
190             return "<%s>" % value
191 
192         if start > 0:
193             return "<T>"
194 
195         # Rust special cases
196         value = _rust_blanket_re.sub("", value)  # prefer trait for blanket impls
197         value = replace_enclosed_string(value, "<", ">", process_generics)
198         return value.split(" as ", 1)[0]
199 
200     function = replace_enclosed_string(function, "<", ">", process_generics)
201 
202     # Remove special `[clone .foo]` annotations for cloned/split functions
203     def process_brackets(value, start):
204         if value.startswith("clone ."):
205             return ""
206         return "[%s]" % value
207 
208     function = replace_enclosed_string(function, "[", "]", process_brackets)
209 
210     is_thunk = "thunk for " in function  # swift
211 
212     tokens = split_func_tokens(function)
213 
214     # MSVC demangles generic operator functions with a space between the
215     # function name and the generics. Ensure that those two components both end
216     # up in the function name.
217     if len(tokens) > 1 and tokens[-1] == "<T>":
218         tokens.pop()
219         tokens[-1] += " <T>"
220 
221     # find the token which is the function name.  Since we chopped of C++
222     # trailers there are only two cases we care about: the token left to
223     # the -> return marker which is for instance used in Swift and if that
224     # is not found, consider the last token to be the function.
225     #
226     # ["unsigned", "int", "whatever"] -> whatever
227     # ["@objc", "whatever", "->", "int"] -> whatever
228     try:
229         func_token = tokens[tokens.index("⟿") - 1]
230     except ValueError:
231         if tokens:
232             func_token = tokens[-1]
233         else:
234             func_token = None
235 
236     if func_token:
237         if func_token.startswith("@") and platform in ("cocoa", "swift"):
238             # Found a Swift attribute instead of a function name, must be an
239             # anonymous function
240             func_token = ("thunk for " if is_thunk else "") + "closure"
241         function = (
242             func_token.replace("⟨", "<")
243             .replace("◯", "()")
244             .replace("⟿", "->")
245             .replace("〔anonymousnamespace〕", "`anonymous namespace'")
246         )
247 
248     # This really should never happen
249     else:
250         function = original_function
251 
252     # trim off rust markers
253     function = _rust_hash.sub("", function)
254 
255     # trim off gnu symbol versioning info
256     function = _gnu_version.sub("", function)
257 
258     # trim off windows decl markers
259     return _windecl_hash.sub("\\1", function)
260 
261 
262 def get_function_name_for_frame(frame, platform=None):
263     """Given a frame object or dictionary this returns the actual function
264     name trimmed.
265     """
266     if hasattr(frame, "get_raw_data"):
267         frame = frame.get_raw_data()
268 
269     # if there is a raw function, prioritize the function unchanged
270     if frame.get("raw_function"):
271         return frame.get("function")
272 
273     # otherwise trim the function on demand
274     rv = frame.get("function")
275     if rv:
276         return trim_function_name(rv, frame.get("platform") or platform)
277 
278 
279 def get_source_link_for_frame(frame: Frame) -> str | None:
280     """If source_link points to a GitHub raw content link, process it so that
281     we can return the GitHub equivalent with the line number, and use it as a
282     stacktrace link. Otherwise, return the link as is.
283     """
284     source_link = getattr(frame, "source_link", None)
285 
286     try:
287         URLValidator()(source_link)
288     except ValidationError:
289         return None
290 
291     parse_result = urlparse(source_link)
292     if parse_result.netloc == "raw.githubusercontent.com":
293         path_parts = parse_result.path.split("/")
294         if path_parts[0] == "":
295             # the path starts with a "/" so the first element is empty string
296             del path_parts[0]
297 
298         # at minimum, the path must have an author/org, a repo, and a file
299         if len(path_parts) >= 3:
300             source_link = "https://www.github.com/" + path_parts[0] + "/" + path_parts[1] + "/blob"
301             for remaining_part in path_parts[2:]:
302                 source_link += "/" + remaining_part
303             if getattr(frame, "lineno", None):
304                 source_link += "#L" + str(frame.lineno)
305     return source_link
306 
307 
308 def set_in_app(frame: dict[str, Any], value: bool) -> None:
309     """Set the value of in_app in the frame to the given value."""
310     orig_in_app = frame.get("in_app")
311     if orig_in_app == value:
312         return
313 
314     orig_in_app = int(orig_in_app) if orig_in_app is not None else -1
315     setdefault_path(frame, "data", "orig_in_app", value=orig_in_app)
316     frame["in_app"] = value
317
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/sentry/stacktraces/functions.py b/src/sentry/stacktraces/functions.py
--- a/src/sentry/stacktraces/functions.py
+++ b/src/sentry/stacktraces/functions.py
@@ -136,6 +136,14 @@
     if function.startswith(("[", "+[", "-[")):
         return function
 
+    # Remove special `[clone .foo]` annotations for cloned/split functions
+    def process_brackets(value, start):
+        if value.startswith("clone ."):
+            return ""
+        return "[%s]" % value
+
+    function = replace_enclosed_string(function, "[", "]", process_brackets).rstrip()
+
     # Chop off C++ trailers
     while True:
         match = _cpp_trailer_re.search(function)
@@ -199,14 +207,6 @@
 
     function = replace_enclosed_string(function, "<", ">", process_generics)
 
-    # Remove special `[clone .foo]` annotations for cloned/split functions
-    def process_brackets(value, start):
-        if value.startswith("clone ."):
-            return ""
-        return "[%s]" % value
-
-    function = replace_enclosed_string(function, "[", "]", process_brackets)
-
     is_thunk = "thunk for " in function  # swift
 
     tokens = split_func_tokens(function)

{"golden_diff": "diff --git a/src/sentry/stacktraces/functions.py b/src/sentry/stacktraces/functions.py\n--- a/src/sentry/stacktraces/functions.py\n+++ b/src/sentry/stacktraces/functions.py\n@@ -136,6 +136,14 @@\n     if function.startswith((\"[\", \"+[\", \"-[\")):\n         return function\n \n+    # Remove special `[clone .foo]` annotations for cloned/split functions\n+    def process_brackets(value, start):\n+        if value.startswith(\"clone .\"):\n+            return \"\"\n+        return \"[%s]\" % value\n+\n+    function = replace_enclosed_string(function, \"[\", \"]\", process_brackets).rstrip()\n+\n     # Chop off C++ trailers\n     while True:\n         match = _cpp_trailer_re.search(function)\n@@ -199,14 +207,6 @@\n \n     function = replace_enclosed_string(function, \"<\", \">\", process_generics)\n \n-    # Remove special `[clone .foo]` annotations for cloned/split functions\n-    def process_brackets(value, start):\n-        if value.startswith(\"clone .\"):\n-            return \"\"\n-        return \"[%s]\" % value\n-\n-    function = replace_enclosed_string(function, \"[\", \"]\", process_brackets)\n-\n     is_thunk = \"thunk for \" in function  # swift\n \n     tokens = split_func_tokens(function)\n", "issue": "native symbolicated 'const' functions incorrectly trimmed\n### Environment\n\nself-hosted (https://develop.sentry.dev/self-hosted/)\n\n### Steps to Reproduce\n\nHave the following verbose native frame `ShellCorona::screenInvariants() const [clone .cold] (shellcorona.cpp:847)`\r\n\r\nThe event has platform:native and the project has platform:native-qt in case that makes a difference\r\n\r\nFull json blob of the frame:\r\n```\r\n            {\r\n              \"function\": \"const\",\r\n              \"raw_function\": \"ShellCorona::screenInvariants() const [clone .cold]\",\r\n              \"symbol\": \"_ZNK11ShellCorona16screenInvariantsEv.cold\",\r\n              \"package\": \"/usr/bin/plasmashell\",\r\n              \"filename\": \"shellcorona.cpp\",\r\n              \"abs_path\": \"obj-x86_64-linux-gnu/shell/shell/shellcorona.cpp\",\r\n              \"lineno\": 847,\r\n              \"in_app\": false,\r\n              \"vars\": {},\r\n              \"data\": {\r\n                \"orig_in_app\": -1,\r\n                \"symbolicator_status\": \"symbolicated\"\r\n              },\r\n              \"instruction_addr\": \"0x558ba221ba82\"\r\n            },\r\n```\n\n### Expected Result\n\nTrimmed name should be something like `ShellCorona::screenInvariants (shellcorona.cpp:847)`\n\n### Actual Result\n\nTrimmed name is `const (shellcorona.cpp:847)`\n\n### Product Area\n\nIssues\n\n### Link\n\n_No response_\n\n### DSN\n\n_No response_\n\n### Version\n\n_No response_\n", "before_files": [{"content": "from __future__ import annotations\n\nimport re\nfrom typing import Any\nfrom urllib.parse import urlparse\n\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import URLValidator\n\nfrom sentry.interfaces.stacktrace import Frame\nfrom sentry.stacktraces.platform import get_behavior_family_for_platform\nfrom sentry.utils.safe import setdefault_path\n\n_windecl_hash = re.compile(r\"^@?(.*?)@[0-9]+$\")\n_rust_hash = re.compile(r\"::h[a-z0-9]{16}$\")\n_gnu_version = re.compile(r\"@@?GLIBC_([0-9.]+)$\")\n_cpp_trailer_re = re.compile(r\"(\\bconst\\b|&)$\")\n_rust_blanket_re = re.compile(r\"^([A-Z] as )\")\n_lambda_re = re.compile(\n    r\"\"\"(?x)\n    # gcc\n    (?:\n        \\{\n            lambda\\(.*?\\)\\#\\d+\n        \\}\n    ) |\n    # msvc\n    (?:\n        \\blambda_[a-f0-9]{32}\\b\n    ) |\n    # clang\n    (?:\n        \\$_\\d+\\b\n    )\n    \"\"\"\n)\n_anon_namespace_re = re.compile(\n    r\"\"\"(?x)\n    \\?A0x[a-f0-9]{8}::\n    \"\"\"\n)\n\n\nPAIRS = {\"(\": \")\", \"{\": \"}\", \"[\": \"]\", \"<\": \">\"}\n\n\ndef replace_enclosed_string(s, start, end, replacement=None):\n    if start not in s:\n        return s\n\n    depth = 0\n\n    rv = []\n    pair_start = None\n    for idx, char in enumerate(s):\n        if char == start:\n            if depth == 0:\n                pair_start = idx\n            depth += 1\n        elif char == end:\n            depth -= 1\n            if depth == 0:\n                if replacement is not None:\n                    if callable(replacement):\n                        rv.append(replacement(s[pair_start + 1 : idx], pair_start))\n                    else:\n                        rv.append(replacement)\n        elif depth == 0:\n            rv.append(char)\n\n    return \"\".join(rv)\n\n\ndef split_func_tokens(s):\n    buf = []\n    rv = []\n    stack = []\n    end = 0\n\n    for idx, char in enumerate(s):\n        if char in PAIRS:\n            stack.append(PAIRS[char])\n        elif stack and char == stack[-1]:\n            stack.pop()\n            if not stack:\n                buf.append(s[end : idx + 1])\n                end = idx + 1\n        elif not stack:\n            if char.isspace():\n                if buf:\n                    rv.append(buf)\n                buf = []\n            else:\n                buf.append(s[end : idx + 1])\n            end = idx + 1\n\n    if buf:\n        rv.append(buf)\n\n    return [\"\".join(x) for x in rv]\n\n\ndef trim_function_name(function, platform, normalize_lambdas=True):\n    \"\"\"Given a function value from the frame's function attribute this returns\n    a trimmed version that can be stored in `function_name`.  This is only used\n    if the client did not supply a value itself already.\n    \"\"\"\n    if platform == \"csharp\":\n        return trim_csharp_function_name(function)\n    if get_behavior_family_for_platform(platform) == \"native\":\n        return trim_native_function_name(function, platform, normalize_lambdas=normalize_lambdas)\n    return function\n\n\ndef trim_csharp_function_name(function):\n    \"\"\"This trims off signatures from C# frames.  This takes advantage of the\n    Unity not emitting any return values and using a space before the argument\n    list.\n\n    Note that there is disagreement between Unity and the main .NET SDK about\n    the function names.  The Unity SDK emits the entire function with module\n    in the `function` name similar to native, the .NET SDK emits it in individual\n    parts of the frame.\n    \"\"\"\n    return function.split(\" (\", 1)[0]\n\n\ndef trim_native_function_name(function, platform, normalize_lambdas=True):\n    if function in (\"<redacted>\", \"<unknown>\"):\n        return function\n\n    original_function = function\n    function = function.strip()\n\n    # Ensure we don't operate on objc functions\n    if function.startswith((\"[\", \"+[\", \"-[\")):\n        return function\n\n    # Chop off C++ trailers\n    while True:\n        match = _cpp_trailer_re.search(function)\n        if match is None:\n            break\n        function = function[: match.start()].rstrip()\n\n    # Because operator<< really screws with our balancing, so let's work\n    # around that by replacing it with a character we do not observe in\n    # `split_func_tokens` or `replace_enclosed_string`.\n    function = (\n        function.replace(\"operator<<\", \"operator\u27e8\u27e8\")\n        .replace(\"operator<\", \"operator\u27e8\")\n        .replace(\"operator()\", \"operator\u25ef\")\n        .replace(\"operator->\", \"operator\u27ff\")\n        .replace(\" -> \", \" \u27ff \")\n        .replace(\"`anonymous namespace'\", \"\u3014anonymousnamespace\u3015\")\n    )\n\n    # normalize C++ lambdas.  This is necessary because different\n    # compilers use different rules for now to name a lambda and they are\n    # all quite inconsistent.  This does not give us perfect answers to\n    # this problem but closer.  In particular msvc will call a lambda\n    # something like `lambda_deadbeefeefffeeffeeff` whereas clang for\n    # instance will name it `main::$_0` which will tell us in which outer\n    # function it was declared.\n    if normalize_lambdas:\n        function = _lambda_re.sub(\"lambda\", function)\n\n    # Normalize MSVC anonymous namespaces from inline functions.  For inline\n    # functions, the compiler inconsistently renders anonymous namespaces with\n    # their hash.  For regular functions,  \"`anonymous namespace'\" is used.\n    # The regular expression matches the trailing \"::\" to avoid accidental\n    # replacement in mangled function names.\n    if normalize_lambdas:\n        function = _anon_namespace_re.sub(\"\u3014anonymousnamespace\u3015::\", function)\n\n    # Remove the arguments if there is one.\n    def process_args(value, start):\n        value = value.strip()\n        if value in (\"anonymous namespace\", \"operator\"):\n            return \"(%s)\" % value\n        return \"\"\n\n    function = replace_enclosed_string(function, \"(\", \")\", process_args)\n\n    # Resolve generic types, but special case rust which uses things like\n    # <Foo as Bar>::baz to denote traits.\n    def process_generics(value, start):\n        # Special case for lambdas\n        if value == \"lambda\" or _lambda_re.match(value):\n            return \"<%s>\" % value\n\n        if start > 0:\n            return \"<T>\"\n\n        # Rust special cases\n        value = _rust_blanket_re.sub(\"\", value)  # prefer trait for blanket impls\n        value = replace_enclosed_string(value, \"<\", \">\", process_generics)\n        return value.split(\" as \", 1)[0]\n\n    function = replace_enclosed_string(function, \"<\", \">\", process_generics)\n\n    # Remove special `[clone .foo]` annotations for cloned/split functions\n    def process_brackets(value, start):\n        if value.startswith(\"clone .\"):\n            return \"\"\n        return \"[%s]\" % value\n\n    function = replace_enclosed_string(function, \"[\", \"]\", process_brackets)\n\n    is_thunk = \"thunk for \" in function  # swift\n\n    tokens = split_func_tokens(function)\n\n    # MSVC demangles generic operator functions with a space between the\n    # function name and the generics. Ensure that those two components both end\n    # up in the function name.\n    if len(tokens) > 1 and tokens[-1] == \"<T>\":\n        tokens.pop()\n        tokens[-1] += \" <T>\"\n\n    # find the token which is the function name.  Since we chopped of C++\n    # trailers there are only two cases we care about: the token left to\n    # the -> return marker which is for instance used in Swift and if that\n    # is not found, consider the last token to be the function.\n    #\n    # [\"unsigned\", \"int\", \"whatever\"] -> whatever\n    # [\"@objc\", \"whatever\", \"->\", \"int\"] -> whatever\n    try:\n        func_token = tokens[tokens.index(\"\u27ff\") - 1]\n    except ValueError:\n        if tokens:\n            func_token = tokens[-1]\n        else:\n            func_token = None\n\n    if func_token:\n        if func_token.startswith(\"@\") and platform in (\"cocoa\", \"swift\"):\n            # Found a Swift attribute instead of a function name, must be an\n            # anonymous function\n            func_token = (\"thunk for \" if is_thunk else \"\") + \"closure\"\n        function = (\n            func_token.replace(\"\u27e8\", \"<\")\n            .replace(\"\u25ef\", \"()\")\n            .replace(\"\u27ff\", \"->\")\n            .replace(\"\u3014anonymousnamespace\u3015\", \"`anonymous namespace'\")\n        )\n\n    # This really should never happen\n    else:\n        function = original_function\n\n    # trim off rust markers\n    function = _rust_hash.sub(\"\", function)\n\n    # trim off gnu symbol versioning info\n    function = _gnu_version.sub(\"\", function)\n\n    # trim off windows decl markers\n    return _windecl_hash.sub(\"\\\\1\", function)\n\n\ndef get_function_name_for_frame(frame, platform=None):\n    \"\"\"Given a frame object or dictionary this returns the actual function\n    name trimmed.\n    \"\"\"\n    if hasattr(frame, \"get_raw_data\"):\n        frame = frame.get_raw_data()\n\n    # if there is a raw function, prioritize the function unchanged\n    if frame.get(\"raw_function\"):\n        return frame.get(\"function\")\n\n    # otherwise trim the function on demand\n    rv = frame.get(\"function\")\n    if rv:\n        return trim_function_name(rv, frame.get(\"platform\") or platform)\n\n\ndef get_source_link_for_frame(frame: Frame) -> str | None:\n    \"\"\"If source_link points to a GitHub raw content link, process it so that\n    we can return the GitHub equivalent with the line number, and use it as a\n    stacktrace link. Otherwise, return the link as is.\n    \"\"\"\n    source_link = getattr(frame, \"source_link\", None)\n\n    try:\n        URLValidator()(source_link)\n    except ValidationError:\n        return None\n\n    parse_result = urlparse(source_link)\n    if parse_result.netloc == \"raw.githubusercontent.com\":\n        path_parts = parse_result.path.split(\"/\")\n        if path_parts[0] == \"\":\n            # the path starts with a \"/\" so the first element is empty string\n            del path_parts[0]\n\n        # at minimum, the path must have an author/org, a repo, and a file\n        if len(path_parts) >= 3:\n            source_link = \"https://www.github.com/\" + path_parts[0] + \"/\" + path_parts[1] + \"/blob\"\n            for remaining_part in path_parts[2:]:\n                source_link += \"/\" + remaining_part\n            if getattr(frame, \"lineno\", None):\n                source_link += \"#L\" + str(frame.lineno)\n    return source_link\n\n\ndef set_in_app(frame: dict[str, Any], value: bool) -> None:\n    \"\"\"Set the value of in_app in the frame to the given value.\"\"\"\n    orig_in_app = frame.get(\"in_app\")\n    if orig_in_app == value:\n        return\n\n    orig_in_app = int(orig_in_app) if orig_in_app is not None else -1\n    setdefault_path(frame, \"data\", \"orig_in_app\", value=orig_in_app)\n    frame[\"in_app\"] = value\n", "path": "src/sentry/stacktraces/functions.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport re\nfrom typing import Any\nfrom urllib.parse import urlparse\n\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import URLValidator\n\nfrom sentry.interfaces.stacktrace import Frame\nfrom sentry.stacktraces.platform import get_behavior_family_for_platform\nfrom sentry.utils.safe import setdefault_path\n\n_windecl_hash = re.compile(r\"^@?(.*?)@[0-9]+$\")\n_rust_hash = re.compile(r\"::h[a-z0-9]{16}$\")\n_gnu_version = re.compile(r\"@@?GLIBC_([0-9.]+)$\")\n_cpp_trailer_re = re.compile(r\"(\\bconst\\b|&)$\")\n_rust_blanket_re = re.compile(r\"^([A-Z] as )\")\n_lambda_re = re.compile(\n    r\"\"\"(?x)\n    # gcc\n    (?:\n        \\{\n            lambda\\(.*?\\)\\#\\d+\n        \\}\n    ) |\n    # msvc\n    (?:\n        \\blambda_[a-f0-9]{32}\\b\n    ) |\n    # clang\n    (?:\n        \\$_\\d+\\b\n    )\n    \"\"\"\n)\n_anon_namespace_re = re.compile(\n    r\"\"\"(?x)\n    \\?A0x[a-f0-9]{8}::\n    \"\"\"\n)\n\n\nPAIRS = {\"(\": \")\", \"{\": \"}\", \"[\": \"]\", \"<\": \">\"}\n\n\ndef replace_enclosed_string(s, start, end, replacement=None):\n    if start not in s:\n        return s\n\n    depth = 0\n\n    rv = []\n    pair_start = None\n    for idx, char in enumerate(s):\n        if char == start:\n            if depth == 0:\n                pair_start = idx\n            depth += 1\n        elif char == end:\n            depth -= 1\n            if depth == 0:\n                if replacement is not None:\n                    if callable(replacement):\n                        rv.append(replacement(s[pair_start + 1 : idx], pair_start))\n                    else:\n                        rv.append(replacement)\n        elif depth == 0:\n            rv.append(char)\n\n    return \"\".join(rv)\n\n\ndef split_func_tokens(s):\n    buf = []\n    rv = []\n    stack = []\n    end = 0\n\n    for idx, char in enumerate(s):\n        if char in PAIRS:\n            stack.append(PAIRS[char])\n        elif stack and char == stack[-1]:\n            stack.pop()\n            if not stack:\n                buf.append(s[end : idx + 1])\n                end = idx + 1\n        elif not stack:\n            if char.isspace():\n                if buf:\n                    rv.append(buf)\n                buf = []\n            else:\n                buf.append(s[end : idx + 1])\n            end = idx + 1\n\n    if buf:\n        rv.append(buf)\n\n    return [\"\".join(x) for x in rv]\n\n\ndef trim_function_name(function, platform, normalize_lambdas=True):\n    \"\"\"Given a function value from the frame's function attribute this returns\n    a trimmed version that can be stored in `function_name`.  This is only used\n    if the client did not supply a value itself already.\n    \"\"\"\n    if platform == \"csharp\":\n        return trim_csharp_function_name(function)\n    if get_behavior_family_for_platform(platform) == \"native\":\n        return trim_native_function_name(function, platform, normalize_lambdas=normalize_lambdas)\n    return function\n\n\ndef trim_csharp_function_name(function):\n    \"\"\"This trims off signatures from C# frames.  This takes advantage of the\n    Unity not emitting any return values and using a space before the argument\n    list.\n\n    Note that there is disagreement between Unity and the main .NET SDK about\n    the function names.  The Unity SDK emits the entire function with module\n    in the `function` name similar to native, the .NET SDK emits it in individual\n    parts of the frame.\n    \"\"\"\n    return function.split(\" (\", 1)[0]\n\n\ndef trim_native_function_name(function, platform, normalize_lambdas=True):\n    if function in (\"<redacted>\", \"<unknown>\"):\n        return function\n\n    original_function = function\n    function = function.strip()\n\n    # Ensure we don't operate on objc functions\n    if function.startswith((\"[\", \"+[\", \"-[\")):\n        return function\n\n    # Remove special `[clone .foo]` annotations for cloned/split functions\n    def process_brackets(value, start):\n        if value.startswith(\"clone .\"):\n            return \"\"\n        return \"[%s]\" % value\n\n    function = replace_enclosed_string(function, \"[\", \"]\", process_brackets).rstrip()\n\n    # Chop off C++ trailers\n    while True:\n        match = _cpp_trailer_re.search(function)\n        if match is None:\n            break\n        function = function[: match.start()].rstrip()\n\n    # Because operator<< really screws with our balancing, so let's work\n    # around that by replacing it with a character we do not observe in\n    # `split_func_tokens` or `replace_enclosed_string`.\n    function = (\n        function.replace(\"operator<<\", \"operator\u27e8\u27e8\")\n        .replace(\"operator<\", \"operator\u27e8\")\n        .replace(\"operator()\", \"operator\u25ef\")\n        .replace(\"operator->\", \"operator\u27ff\")\n        .replace(\" -> \", \" \u27ff \")\n        .replace(\"`anonymous namespace'\", \"\u3014anonymousnamespace\u3015\")\n    )\n\n    # normalize C++ lambdas.  This is necessary because different\n    # compilers use different rules for now to name a lambda and they are\n    # all quite inconsistent.  This does not give us perfect answers to\n    # this problem but closer.  In particular msvc will call a lambda\n    # something like `lambda_deadbeefeefffeeffeeff` whereas clang for\n    # instance will name it `main::$_0` which will tell us in which outer\n    # function it was declared.\n    if normalize_lambdas:\n        function = _lambda_re.sub(\"lambda\", function)\n\n    # Normalize MSVC anonymous namespaces from inline functions.  For inline\n    # functions, the compiler inconsistently renders anonymous namespaces with\n    # their hash.  For regular functions,  \"`anonymous namespace'\" is used.\n    # The regular expression matches the trailing \"::\" to avoid accidental\n    # replacement in mangled function names.\n    if normalize_lambdas:\n        function = _anon_namespace_re.sub(\"\u3014anonymousnamespace\u3015::\", function)\n\n    # Remove the arguments if there is one.\n    def process_args(value, start):\n        value = value.strip()\n        if value in (\"anonymous namespace\", \"operator\"):\n            return \"(%s)\" % value\n        return \"\"\n\n    function = replace_enclosed_string(function, \"(\", \")\", process_args)\n\n    # Resolve generic types, but special case rust which uses things like\n    # <Foo as Bar>::baz to denote traits.\n    def process_generics(value, start):\n        # Special case for lambdas\n        if value == \"lambda\" or _lambda_re.match(value):\n            return \"<%s>\" % value\n\n        if start > 0:\n            return \"<T>\"\n\n        # Rust special cases\n        value = _rust_blanket_re.sub(\"\", value)  # prefer trait for blanket impls\n        value = replace_enclosed_string(value, \"<\", \">\", process_generics)\n        return value.split(\" as \", 1)[0]\n\n    function = replace_enclosed_string(function, \"<\", \">\", process_generics)\n\n    is_thunk = \"thunk for \" in function  # swift\n\n    tokens = split_func_tokens(function)\n\n    # MSVC demangles generic operator functions with a space between the\n    # function name and the generics. Ensure that those two components both end\n    # up in the function name.\n    if len(tokens) > 1 and tokens[-1] == \"<T>\":\n        tokens.pop()\n        tokens[-1] += \" <T>\"\n\n    # find the token which is the function name.  Since we chopped of C++\n    # trailers there are only two cases we care about: the token left to\n    # the -> return marker which is for instance used in Swift and if that\n    # is not found, consider the last token to be the function.\n    #\n    # [\"unsigned\", \"int\", \"whatever\"] -> whatever\n    # [\"@objc\", \"whatever\", \"->\", \"int\"] -> whatever\n    try:\n        func_token = tokens[tokens.index(\"\u27ff\") - 1]\n    except ValueError:\n        if tokens:\n            func_token = tokens[-1]\n        else:\n            func_token = None\n\n    if func_token:\n        if func_token.startswith(\"@\") and platform in (\"cocoa\", \"swift\"):\n            # Found a Swift attribute instead of a function name, must be an\n            # anonymous function\n            func_token = (\"thunk for \" if is_thunk else \"\") + \"closure\"\n        function = (\n            func_token.replace(\"\u27e8\", \"<\")\n            .replace(\"\u25ef\", \"()\")\n            .replace(\"\u27ff\", \"->\")\n            .replace(\"\u3014anonymousnamespace\u3015\", \"`anonymous namespace'\")\n        )\n\n    # This really should never happen\n    else:\n        function = original_function\n\n    # trim off rust markers\n    function = _rust_hash.sub(\"\", function)\n\n    # trim off gnu symbol versioning info\n    function = _gnu_version.sub(\"\", function)\n\n    # trim off windows decl markers\n    return _windecl_hash.sub(\"\\\\1\", function)\n\n\ndef get_function_name_for_frame(frame, platform=None):\n    \"\"\"Given a frame object or dictionary this returns the actual function\n    name trimmed.\n    \"\"\"\n    if hasattr(frame, \"get_raw_data\"):\n        frame = frame.get_raw_data()\n\n    # if there is a raw function, prioritize the function unchanged\n    if frame.get(\"raw_function\"):\n        return frame.get(\"function\")\n\n    # otherwise trim the function on demand\n    rv = frame.get(\"function\")\n    if rv:\n        return trim_function_name(rv, frame.get(\"platform\") or platform)\n\n\ndef get_source_link_for_frame(frame: Frame) -> str | None:\n    \"\"\"If source_link points to a GitHub raw content link, process it so that\n    we can return the GitHub equivalent with the line number, and use it as a\n    stacktrace link. Otherwise, return the link as is.\n    \"\"\"\n    source_link = getattr(frame, \"source_link\", None)\n\n    try:\n        URLValidator()(source_link)\n    except ValidationError:\n        return None\n\n    parse_result = urlparse(source_link)\n    if parse_result.netloc == \"raw.githubusercontent.com\":\n        path_parts = parse_result.path.split(\"/\")\n        if path_parts[0] == \"\":\n            # the path starts with a \"/\" so the first element is empty string\n            del path_parts[0]\n\n        # at minimum, the path must have an author/org, a repo, and a file\n        if len(path_parts) >= 3:\n            source_link = \"https://www.github.com/\" + path_parts[0] + \"/\" + path_parts[1] + \"/blob\"\n            for remaining_part in path_parts[2:]:\n                source_link += \"/\" + remaining_part\n            if getattr(frame, \"lineno\", None):\n                source_link += \"#L\" + str(frame.lineno)\n    return source_link\n\n\ndef set_in_app(frame: dict[str, Any], value: bool) -> None:\n    \"\"\"Set the value of in_app in the frame to the given value.\"\"\"\n    orig_in_app = frame.get(\"in_app\")\n    if orig_in_app == value:\n        return\n\n    orig_in_app = int(orig_in_app) if orig_in_app is not None else -1\n    setdefault_path(frame, \"data\", \"orig_in_app\", value=orig_in_app)\n    frame[\"in_app\"] = value\n", "path": "src/sentry/stacktraces/functions.py"}]}