crosshair-tool 0.0.99__cp312-cp312-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. _crosshair_tracers.cpython-312-darwin.so +0 -0
  2. crosshair/__init__.py +42 -0
  3. crosshair/__main__.py +8 -0
  4. crosshair/_mark_stacks.h +790 -0
  5. crosshair/_preliminaries_test.py +18 -0
  6. crosshair/_tracers.h +94 -0
  7. crosshair/_tracers_pycompat.h +522 -0
  8. crosshair/_tracers_test.py +138 -0
  9. crosshair/abcstring.py +245 -0
  10. crosshair/auditwall.py +190 -0
  11. crosshair/auditwall_test.py +77 -0
  12. crosshair/codeconfig.py +113 -0
  13. crosshair/codeconfig_test.py +117 -0
  14. crosshair/condition_parser.py +1237 -0
  15. crosshair/condition_parser_test.py +497 -0
  16. crosshair/conftest.py +30 -0
  17. crosshair/copyext.py +155 -0
  18. crosshair/copyext_test.py +84 -0
  19. crosshair/core.py +1763 -0
  20. crosshair/core_and_libs.py +149 -0
  21. crosshair/core_regestered_types_test.py +82 -0
  22. crosshair/core_test.py +1316 -0
  23. crosshair/diff_behavior.py +314 -0
  24. crosshair/diff_behavior_test.py +261 -0
  25. crosshair/dynamic_typing.py +346 -0
  26. crosshair/dynamic_typing_test.py +210 -0
  27. crosshair/enforce.py +282 -0
  28. crosshair/enforce_test.py +182 -0
  29. crosshair/examples/PEP316/__init__.py +1 -0
  30. crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
  31. crosshair/examples/PEP316/bugs_detected/getattr_magic.py +16 -0
  32. crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +31 -0
  33. crosshair/examples/PEP316/bugs_detected/shopping_cart.py +24 -0
  34. crosshair/examples/PEP316/bugs_detected/showcase.py +39 -0
  35. crosshair/examples/PEP316/correct_code/__init__.py +0 -0
  36. crosshair/examples/PEP316/correct_code/arith.py +60 -0
  37. crosshair/examples/PEP316/correct_code/chess.py +77 -0
  38. crosshair/examples/PEP316/correct_code/nesting_inference.py +17 -0
  39. crosshair/examples/PEP316/correct_code/numpy_examples.py +132 -0
  40. crosshair/examples/PEP316/correct_code/rolling_average.py +35 -0
  41. crosshair/examples/PEP316/correct_code/showcase.py +104 -0
  42. crosshair/examples/__init__.py +0 -0
  43. crosshair/examples/check_examples_test.py +146 -0
  44. crosshair/examples/deal/__init__.py +1 -0
  45. crosshair/examples/icontract/__init__.py +1 -0
  46. crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
  47. crosshair/examples/icontract/bugs_detected/showcase.py +41 -0
  48. crosshair/examples/icontract/bugs_detected/wrong_sign.py +8 -0
  49. crosshair/examples/icontract/correct_code/__init__.py +0 -0
  50. crosshair/examples/icontract/correct_code/arith.py +51 -0
  51. crosshair/examples/icontract/correct_code/showcase.py +94 -0
  52. crosshair/fnutil.py +391 -0
  53. crosshair/fnutil_test.py +75 -0
  54. crosshair/fuzz_core_test.py +516 -0
  55. crosshair/libimpl/__init__.py +0 -0
  56. crosshair/libimpl/arraylib.py +161 -0
  57. crosshair/libimpl/binascii_ch_test.py +30 -0
  58. crosshair/libimpl/binascii_test.py +67 -0
  59. crosshair/libimpl/binasciilib.py +150 -0
  60. crosshair/libimpl/bisectlib_test.py +23 -0
  61. crosshair/libimpl/builtinslib.py +5228 -0
  62. crosshair/libimpl/builtinslib_ch_test.py +1191 -0
  63. crosshair/libimpl/builtinslib_test.py +3735 -0
  64. crosshair/libimpl/codecslib.py +86 -0
  65. crosshair/libimpl/codecslib_test.py +86 -0
  66. crosshair/libimpl/collectionslib.py +264 -0
  67. crosshair/libimpl/collectionslib_ch_test.py +252 -0
  68. crosshair/libimpl/collectionslib_test.py +332 -0
  69. crosshair/libimpl/copylib.py +23 -0
  70. crosshair/libimpl/copylib_test.py +18 -0
  71. crosshair/libimpl/datetimelib.py +2559 -0
  72. crosshair/libimpl/datetimelib_ch_test.py +354 -0
  73. crosshair/libimpl/datetimelib_test.py +112 -0
  74. crosshair/libimpl/decimallib.py +5257 -0
  75. crosshair/libimpl/decimallib_ch_test.py +78 -0
  76. crosshair/libimpl/decimallib_test.py +76 -0
  77. crosshair/libimpl/encodings/__init__.py +23 -0
  78. crosshair/libimpl/encodings/_encutil.py +187 -0
  79. crosshair/libimpl/encodings/ascii.py +44 -0
  80. crosshair/libimpl/encodings/latin_1.py +40 -0
  81. crosshair/libimpl/encodings/utf_8.py +93 -0
  82. crosshair/libimpl/encodings_ch_test.py +83 -0
  83. crosshair/libimpl/fractionlib.py +16 -0
  84. crosshair/libimpl/fractionlib_test.py +80 -0
  85. crosshair/libimpl/functoolslib.py +34 -0
  86. crosshair/libimpl/functoolslib_test.py +56 -0
  87. crosshair/libimpl/hashliblib.py +30 -0
  88. crosshair/libimpl/hashliblib_test.py +18 -0
  89. crosshair/libimpl/heapqlib.py +47 -0
  90. crosshair/libimpl/heapqlib_test.py +21 -0
  91. crosshair/libimpl/importliblib.py +18 -0
  92. crosshair/libimpl/importliblib_test.py +38 -0
  93. crosshair/libimpl/iolib.py +216 -0
  94. crosshair/libimpl/iolib_ch_test.py +128 -0
  95. crosshair/libimpl/iolib_test.py +19 -0
  96. crosshair/libimpl/ipaddresslib.py +8 -0
  97. crosshair/libimpl/itertoolslib.py +44 -0
  98. crosshair/libimpl/itertoolslib_test.py +44 -0
  99. crosshair/libimpl/jsonlib.py +984 -0
  100. crosshair/libimpl/jsonlib_ch_test.py +42 -0
  101. crosshair/libimpl/jsonlib_test.py +51 -0
  102. crosshair/libimpl/mathlib.py +179 -0
  103. crosshair/libimpl/mathlib_ch_test.py +44 -0
  104. crosshair/libimpl/mathlib_test.py +67 -0
  105. crosshair/libimpl/oslib.py +7 -0
  106. crosshair/libimpl/pathliblib_test.py +10 -0
  107. crosshair/libimpl/randomlib.py +178 -0
  108. crosshair/libimpl/randomlib_test.py +120 -0
  109. crosshair/libimpl/relib.py +846 -0
  110. crosshair/libimpl/relib_ch_test.py +169 -0
  111. crosshair/libimpl/relib_test.py +493 -0
  112. crosshair/libimpl/timelib.py +72 -0
  113. crosshair/libimpl/timelib_test.py +82 -0
  114. crosshair/libimpl/typeslib.py +15 -0
  115. crosshair/libimpl/typeslib_test.py +36 -0
  116. crosshair/libimpl/unicodedatalib.py +75 -0
  117. crosshair/libimpl/unicodedatalib_test.py +42 -0
  118. crosshair/libimpl/urlliblib.py +23 -0
  119. crosshair/libimpl/urlliblib_test.py +19 -0
  120. crosshair/libimpl/weakreflib.py +13 -0
  121. crosshair/libimpl/weakreflib_test.py +69 -0
  122. crosshair/libimpl/zliblib.py +15 -0
  123. crosshair/libimpl/zliblib_test.py +13 -0
  124. crosshair/lsp_server.py +261 -0
  125. crosshair/lsp_server_test.py +30 -0
  126. crosshair/main.py +973 -0
  127. crosshair/main_test.py +543 -0
  128. crosshair/objectproxy.py +376 -0
  129. crosshair/objectproxy_test.py +41 -0
  130. crosshair/opcode_intercept.py +601 -0
  131. crosshair/opcode_intercept_test.py +304 -0
  132. crosshair/options.py +218 -0
  133. crosshair/options_test.py +10 -0
  134. crosshair/patch_equivalence_test.py +75 -0
  135. crosshair/path_cover.py +209 -0
  136. crosshair/path_cover_test.py +138 -0
  137. crosshair/path_search.py +161 -0
  138. crosshair/path_search_test.py +52 -0
  139. crosshair/pathing_oracle.py +271 -0
  140. crosshair/pathing_oracle_test.py +21 -0
  141. crosshair/pure_importer.py +27 -0
  142. crosshair/pure_importer_test.py +16 -0
  143. crosshair/py.typed +0 -0
  144. crosshair/register_contract.py +273 -0
  145. crosshair/register_contract_test.py +190 -0
  146. crosshair/simplestructs.py +1165 -0
  147. crosshair/simplestructs_test.py +283 -0
  148. crosshair/smtlib.py +24 -0
  149. crosshair/smtlib_test.py +14 -0
  150. crosshair/statespace.py +1199 -0
  151. crosshair/statespace_test.py +108 -0
  152. crosshair/stubs_parser.py +352 -0
  153. crosshair/stubs_parser_test.py +43 -0
  154. crosshair/test_util.py +329 -0
  155. crosshair/test_util_test.py +26 -0
  156. crosshair/tools/__init__.py +0 -0
  157. crosshair/tools/check_help_in_doc.py +264 -0
  158. crosshair/tools/check_init_and_setup_coincide.py +119 -0
  159. crosshair/tools/generate_demo_table.py +127 -0
  160. crosshair/tracers.py +544 -0
  161. crosshair/tracers_test.py +154 -0
  162. crosshair/type_repo.py +151 -0
  163. crosshair/unicode_categories.py +589 -0
  164. crosshair/unicode_categories_test.py +27 -0
  165. crosshair/util.py +741 -0
  166. crosshair/util_test.py +173 -0
  167. crosshair/watcher.py +307 -0
  168. crosshair/watcher_test.py +107 -0
  169. crosshair/z3util.py +76 -0
  170. crosshair/z3util_test.py +11 -0
  171. crosshair_tool-0.0.99.dist-info/METADATA +144 -0
  172. crosshair_tool-0.0.99.dist-info/RECORD +176 -0
  173. crosshair_tool-0.0.99.dist-info/WHEEL +6 -0
  174. crosshair_tool-0.0.99.dist-info/entry_points.txt +3 -0
  175. crosshair_tool-0.0.99.dist-info/licenses/LICENSE +93 -0
  176. crosshair_tool-0.0.99.dist-info/top_level.txt +2 -0
@@ -0,0 +1,261 @@
1
+ import logging
2
+ import os
3
+ import pathlib
4
+ import re
5
+ import sys
6
+ import time
7
+ from collections import defaultdict
8
+ from dataclasses import dataclass, field
9
+ from pathlib import Path
10
+ from threading import Thread
11
+ from typing import Any, Counter, Dict, List, Optional
12
+ from urllib.parse import unquote, urlparse
13
+
14
+ from lsprotocol.types import (
15
+ SHUTDOWN,
16
+ TEXT_DOCUMENT_DID_CHANGE,
17
+ TEXT_DOCUMENT_DID_CLOSE,
18
+ TEXT_DOCUMENT_DID_OPEN,
19
+ TEXT_DOCUMENT_DID_SAVE,
20
+ Diagnostic,
21
+ DiagnosticSeverity,
22
+ DidChangeTextDocumentParams,
23
+ DidCloseTextDocumentParams,
24
+ DidOpenTextDocumentParams,
25
+ Position,
26
+ Range,
27
+ )
28
+
29
+ try:
30
+ from pygls.lsp.server import LanguageServer # (v2.x)
31
+ except ImportError:
32
+ from pygls.server import LanguageServer # (v1.x)
33
+
34
+ from crosshair import __version__, env_info
35
+ from crosshair.options import DEFAULT_OPTIONS, AnalysisOptionSet
36
+ from crosshair.statespace import AnalysisMessage, MessageType
37
+ from crosshair.watcher import Watcher
38
+
39
+ # logging.basicConfig(
40
+ # filename="/Users/pschanely/pygls.log", filemode="w", level=logging.DEBUG
41
+ # )
42
+
43
+
44
+ class CrossHairLanguageServer(LanguageServer):
45
+ def __init__(self, options: AnalysisOptionSet):
46
+ self.options = options
47
+ super().__init__("CrossHairServer", __version__)
48
+
49
+ def window_log_message(self, message: str):
50
+ # Just for version 1 & 2 compatibility
51
+ if hasattr(self, "show_message_log"):
52
+ self.show_message_log(message)
53
+ else:
54
+ super().window_log_message(message)
55
+
56
+ CMD_REGISTER_COMPLETIONS = "registerCompletions"
57
+ CMD_UNREGISTER_COMPLETIONS = "unregisterCompletions"
58
+
59
+
60
+ def get_diagnostic(message: AnalysisMessage, doclines: List[str]) -> Diagnostic:
61
+ line = message.line - 1
62
+ col = endcol = message.column
63
+ if col == 0:
64
+ if line < len(doclines):
65
+ line_text = doclines[line]
66
+ match = re.compile(r"^\s*(.*?)\s*$").fullmatch(line_text)
67
+ if match:
68
+ col, endcol = match.start(1), match.end(1)
69
+ if message.state < MessageType.PRE_UNSAT:
70
+ severity = DiagnosticSeverity.Information
71
+ elif message.state == MessageType.PRE_UNSAT:
72
+ severity = DiagnosticSeverity.Warning
73
+ else:
74
+ severity = DiagnosticSeverity.Error
75
+ return Diagnostic(
76
+ range=Range(
77
+ start=Position(line=line, character=col),
78
+ end=Position(line=line, character=endcol),
79
+ ),
80
+ severity=severity,
81
+ message=message.message,
82
+ source="CrossHair",
83
+ )
84
+
85
+
86
+ def publish_messages(
87
+ messages: Dict[str, Optional[Dict[int, AnalysisMessage]]],
88
+ server: CrossHairLanguageServer,
89
+ ):
90
+ for uri, file_messages in list(messages.items()):
91
+ doc = server.workspace.documents.get(uri, None)
92
+ if file_messages is None:
93
+ # closed/editing, and client already notified as empty
94
+ continue
95
+ diagnostics = []
96
+ for message in file_messages.values():
97
+ if message.state < MessageType.PRE_UNSAT:
98
+ continue
99
+ # TODO: consider server.window_log_message()ing the long description
100
+ diagnostics.append(get_diagnostic(message, doc.lines if doc else []))
101
+ server.publish_diagnostics(uri, diagnostics)
102
+ if not diagnostics:
103
+ # After we publish an empty set, it's safe to forget about the file:
104
+ del messages[uri]
105
+
106
+
107
+ @dataclass
108
+ class LocalState:
109
+ watcher: Watcher
110
+ server: CrossHairLanguageServer
111
+ active_messages: Dict[str, Optional[Dict[int, AnalysisMessage]]] = field(
112
+ default_factory=lambda: defaultdict(dict)
113
+ )
114
+ should_shutdown: bool = False
115
+
116
+ def start_loop_thread(self):
117
+ self.loop = Thread(target=self.run_watch_loop)
118
+ self.loop.start()
119
+
120
+ def shutdown(self):
121
+ self.should_shutdown = True
122
+ self.watcher.shutdown()
123
+ self.loop.join(3.0) # run_iteration should check the flag 1x / second
124
+
125
+ def run_watch_loop(
126
+ self,
127
+ max_watch_iterations: int = sys.maxsize,
128
+ ) -> None:
129
+ def log(*a):
130
+ pass # self.server.window_log_message(*a)
131
+
132
+ log("loop thread started")
133
+ watcher = self.watcher
134
+ server = self.server
135
+ active_messages = self.active_messages
136
+ restart = True
137
+ stats: Counter[str] = Counter()
138
+ for _i in range(max_watch_iterations):
139
+ if self.should_shutdown:
140
+ return
141
+ if restart:
142
+ numfiles = len(watcher._modtimes)
143
+ server.window_log_message(
144
+ f"Scanning {numfiles} file(s) for properties to check."
145
+ )
146
+ max_uninteresting_iterations = (
147
+ DEFAULT_OPTIONS.get_max_uninteresting_iterations()
148
+ )
149
+ restart = False
150
+ stats = Counter()
151
+ for k, v in list(active_messages.items()):
152
+ active_messages[k] = None if v is None else {}
153
+ else:
154
+ time.sleep(0.25)
155
+ max_uninteresting_iterations = min(
156
+ sys.maxsize, 2 * max_uninteresting_iterations
157
+ )
158
+ log(f"iteration starting" + str(_i))
159
+ for curstats, messages in watcher.run_iteration(
160
+ max_uninteresting_iterations
161
+ ):
162
+ log(f"iteration yielded {curstats, messages}")
163
+ stats.update(curstats)
164
+ for message in messages:
165
+ filename, line = (message.filename, message.line)
166
+ file_messages = active_messages[Path(filename).as_uri()]
167
+ if file_messages is not None and (
168
+ line not in file_messages
169
+ or file_messages[line].state < message.state
170
+ ):
171
+ file_messages[line] = message
172
+ numpaths = stats["num_paths"]
173
+ if self.should_shutdown:
174
+ return
175
+ if numpaths > 0:
176
+ status = f"Analyzed {numpaths} paths in {len(watcher._modtimes)} files."
177
+ server.window_log_message(status)
178
+ publish_messages(active_messages, server)
179
+ if watcher._change_flag:
180
+ watcher._change_flag = False
181
+ restart = True
182
+ log(f"done run loop")
183
+
184
+
185
+ _LS: Optional[LocalState] = None
186
+
187
+
188
+ def getlocalstate(server: CrossHairLanguageServer) -> LocalState:
189
+ global _LS
190
+ if _LS is None:
191
+ server.window_log_message(env_info())
192
+ watcher = Watcher([], server.options)
193
+ watcher.startpool()
194
+ _LS = LocalState(watcher, server)
195
+ _LS.start_loop_thread()
196
+ else:
197
+ _LS.server = server
198
+ return _LS
199
+
200
+
201
+ def update_paths(server: CrossHairLanguageServer):
202
+ paths = []
203
+ for uri, doc in server.workspace.documents.items():
204
+ if not doc.filename.endswith(".py"):
205
+ continue
206
+ parsed = urlparse(uri)
207
+ if parsed.netloc != "":
208
+ continue
209
+ path = unquote(parsed.path)
210
+ if os.name == "nt":
211
+ while path.startswith("/"):
212
+ path = path[1:] # Remove leading slashes on windows
213
+ path = path.replace("/", "\\")
214
+ paths.append(pathlib.Path(path))
215
+ watcher = getlocalstate(server).watcher
216
+ server.window_log_message("New path set: " + repr(paths))
217
+ watcher.update_paths(paths)
218
+
219
+
220
+ def create_lsp_server(options: AnalysisOptionSet) -> CrossHairLanguageServer:
221
+
222
+ crosshair_lsp_server = CrossHairLanguageServer(options)
223
+
224
+ @crosshair_lsp_server.feature(TEXT_DOCUMENT_DID_CHANGE)
225
+ def did_change(
226
+ server: CrossHairLanguageServer, params: DidChangeTextDocumentParams
227
+ ):
228
+ # server.window_log_message("did_change")
229
+ uri = params.text_document.uri
230
+ getlocalstate(server).active_messages[uri] = None
231
+ server.publish_diagnostics(uri, [])
232
+
233
+ @crosshair_lsp_server.feature(TEXT_DOCUMENT_DID_CLOSE)
234
+ def did_close(server: CrossHairLanguageServer, params: DidCloseTextDocumentParams):
235
+ # server.window_log_message("did_close")
236
+ uri = params.text_document.uri
237
+ getlocalstate(server).active_messages[uri] = None
238
+ server.publish_diagnostics(uri, [])
239
+ update_paths(server)
240
+
241
+ @crosshair_lsp_server.feature(TEXT_DOCUMENT_DID_OPEN)
242
+ def did_open(server: CrossHairLanguageServer, params: DidOpenTextDocumentParams):
243
+ uri = params.text_document.uri
244
+ getlocalstate(server).active_messages[uri] = {}
245
+ update_paths(server)
246
+
247
+ @crosshair_lsp_server.feature(TEXT_DOCUMENT_DID_SAVE)
248
+ def did_save(server: CrossHairLanguageServer, params: DidOpenTextDocumentParams):
249
+ uri = params.text_document.uri
250
+ update_paths(server)
251
+ getlocalstate(server).active_messages[uri] = {}
252
+ server.publish_diagnostics(uri, [])
253
+
254
+ @crosshair_lsp_server.feature(SHUTDOWN)
255
+ def did_shutdown(
256
+ server: CrossHairLanguageServer,
257
+ params: Any,
258
+ ):
259
+ getlocalstate(server).shutdown()
260
+
261
+ return crosshair_lsp_server
@@ -0,0 +1,30 @@
1
+ import pytest
2
+ from lsprotocol.types import Diagnostic, DiagnosticSeverity, Position, Range
3
+
4
+ from crosshair.lsp_server import LocalState, create_lsp_server, get_diagnostic
5
+ from crosshair.options import AnalysisOptionSet
6
+ from crosshair.statespace import AnalysisMessage, MessageType
7
+ from crosshair.watcher import Watcher
8
+
9
+
10
+ @pytest.fixture
11
+ def state():
12
+ server = create_lsp_server(AnalysisOptionSet())
13
+ return LocalState(Watcher([]), server)
14
+
15
+
16
+ def test_get_diagnostic():
17
+ msg = AnalysisMessage(MessageType.POST_ERR, "exception raised", __file__, 2, 0, "")
18
+ assert get_diagnostic(msg, ["one", " two ", "three"]) == Diagnostic(
19
+ range=Range(
20
+ start=Position(line=1, character=2),
21
+ end=Position(line=1, character=5),
22
+ ),
23
+ severity=DiagnosticSeverity.Error,
24
+ message="exception raised",
25
+ source="CrossHair",
26
+ )
27
+
28
+
29
+ def test_watch_loop(state: LocalState):
30
+ state.run_watch_loop(max_watch_iterations=1)