laser 0.7.0.pre1

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 (319) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +661 -0
  5. data/README.md +158 -0
  6. data/Rakefile +104 -0
  7. data/VERSION +1 -0
  8. data/bin/laser +7 -0
  9. data/design_docs/goals.md +57 -0
  10. data/design_docs/object_regex.md +426 -0
  11. data/design_docs/type_annotations.md +80 -0
  12. data/ext/laser/BasicBlock.cpp +572 -0
  13. data/ext/laser/BasicBlock.h +118 -0
  14. data/ext/laser/extconf.rb +3 -0
  15. data/features/laser.feature +25 -0
  16. data/features/step_definitions/laser_steps.rb +39 -0
  17. data/features/support/env.rb +14 -0
  18. data/features/support/testdata/1_input +1 -0
  19. data/features/support/testdata/1_output +1 -0
  20. data/features/support/testdata/2_input +4 -0
  21. data/features/support/testdata/2_output +4 -0
  22. data/features/support/testdata/3_input +8 -0
  23. data/features/support/testdata/3_output +11 -0
  24. data/features/support/testdata/4_input +5 -0
  25. data/features/support/testdata/4_output +5 -0
  26. data/features/support/testdata/5_input +13 -0
  27. data/laser.gemspec +382 -0
  28. data/lib/laser.rb +98 -0
  29. data/lib/laser/analysis/annotations.rb +95 -0
  30. data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
  31. data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
  32. data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
  33. data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
  34. data/lib/laser/analysis/argument_expansion.rb +132 -0
  35. data/lib/laser/analysis/arity.rb +34 -0
  36. data/lib/laser/analysis/bindings.rb +144 -0
  37. data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
  38. data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
  39. data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
  40. data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
  41. data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
  42. data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
  43. data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
  44. data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
  45. data/lib/laser/analysis/comments.rb +35 -0
  46. data/lib/laser/analysis/control_flow.rb +28 -0
  47. data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
  48. data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
  49. data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
  50. data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
  51. data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
  52. data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
  53. data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
  54. data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
  55. data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
  56. data/lib/laser/analysis/control_flow/simulation.rb +385 -0
  57. data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
  58. data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
  59. data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
  60. data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
  61. data/lib/laser/analysis/errors.rb +131 -0
  62. data/lib/laser/analysis/laser_utils.rb +18 -0
  63. data/lib/laser/analysis/lexical_analysis.rb +172 -0
  64. data/lib/laser/analysis/method_call.rb +68 -0
  65. data/lib/laser/analysis/protocol_registry.rb +30 -0
  66. data/lib/laser/analysis/scope.rb +118 -0
  67. data/lib/laser/analysis/sexp.rb +159 -0
  68. data/lib/laser/analysis/sexp_analysis.rb +40 -0
  69. data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
  70. data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
  71. data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
  72. data/lib/laser/analysis/signature.rb +76 -0
  73. data/lib/laser/analysis/special_methods/send.rb +67 -0
  74. data/lib/laser/analysis/unused_methods.rb +21 -0
  75. data/lib/laser/analysis/visitor.rb +141 -0
  76. data/lib/laser/annotation_parser/annotations.treetop +126 -0
  77. data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
  78. data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
  79. data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
  80. data/lib/laser/annotation_parser/overload.treetop +24 -0
  81. data/lib/laser/annotation_parser/overload_parser.rb +167 -0
  82. data/lib/laser/annotation_parser/parsers.rb +6 -0
  83. data/lib/laser/annotation_parser/structural.treetop +37 -0
  84. data/lib/laser/annotation_parser/structural_parser.rb +406 -0
  85. data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
  86. data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
  87. data/lib/laser/rake/task.rb +46 -0
  88. data/lib/laser/runner.rb +189 -0
  89. data/lib/laser/scanner.rb +169 -0
  90. data/lib/laser/standard_library/_thread.rb +110 -0
  91. data/lib/laser/standard_library/abbrev.rb +103 -0
  92. data/lib/laser/standard_library/array.rb +418 -0
  93. data/lib/laser/standard_library/base64.rb +91 -0
  94. data/lib/laser/standard_library/basic_object.rb +55 -0
  95. data/lib/laser/standard_library/benchmark.rb +556 -0
  96. data/lib/laser/standard_library/bignum.rb +185 -0
  97. data/lib/laser/standard_library/cgi.rb +275 -0
  98. data/lib/laser/standard_library/cgi/cookie.rb +147 -0
  99. data/lib/laser/standard_library/cgi/core.rb +791 -0
  100. data/lib/laser/standard_library/cgi/html.rb +1021 -0
  101. data/lib/laser/standard_library/cgi/session.rb +537 -0
  102. data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
  103. data/lib/laser/standard_library/cgi/util.rb +188 -0
  104. data/lib/laser/standard_library/class_definitions.rb +333 -0
  105. data/lib/laser/standard_library/comparable.rb +125 -0
  106. data/lib/laser/standard_library/complex.rb +162 -0
  107. data/lib/laser/standard_library/enumerable.rb +178 -0
  108. data/lib/laser/standard_library/exceptions.rb +135 -0
  109. data/lib/laser/standard_library/fixnum.rb +188 -0
  110. data/lib/laser/standard_library/float.rb +180 -0
  111. data/lib/laser/standard_library/hash.rb +237 -0
  112. data/lib/laser/standard_library/integer.rb +123 -0
  113. data/lib/laser/standard_library/laser_magic.rb +7 -0
  114. data/lib/laser/standard_library/nil_false_true.rb +113 -0
  115. data/lib/laser/standard_library/numbers.rb +192 -0
  116. data/lib/laser/standard_library/proc.rb +31 -0
  117. data/lib/laser/standard_library/set.rb +1348 -0
  118. data/lib/laser/standard_library/string.rb +666 -0
  119. data/lib/laser/standard_library/stringio.rb +2 -0
  120. data/lib/laser/standard_library/symbol.rb +125 -0
  121. data/lib/laser/standard_library/tsort.rb +242 -0
  122. data/lib/laser/support/acts_as_struct.rb +66 -0
  123. data/lib/laser/support/frequency.rb +55 -0
  124. data/lib/laser/support/inheritable_attributes.rb +145 -0
  125. data/lib/laser/support/module_extensions.rb +94 -0
  126. data/lib/laser/support/placeholder_object.rb +13 -0
  127. data/lib/laser/third_party/rgl/adjacency.rb +221 -0
  128. data/lib/laser/third_party/rgl/base.rb +228 -0
  129. data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
  130. data/lib/laser/third_party/rgl/condensation.rb +47 -0
  131. data/lib/laser/third_party/rgl/connected_components.rb +138 -0
  132. data/lib/laser/third_party/rgl/control_flow.rb +170 -0
  133. data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
  134. data/lib/laser/third_party/rgl/dominators.rb +124 -0
  135. data/lib/laser/third_party/rgl/dot.rb +93 -0
  136. data/lib/laser/third_party/rgl/graphxml.rb +51 -0
  137. data/lib/laser/third_party/rgl/implicit.rb +174 -0
  138. data/lib/laser/third_party/rgl/mutable.rb +117 -0
  139. data/lib/laser/third_party/rgl/rdot.rb +445 -0
  140. data/lib/laser/third_party/rgl/topsort.rb +72 -0
  141. data/lib/laser/third_party/rgl/transitivity.rb +180 -0
  142. data/lib/laser/third_party/rgl/traversal.rb +348 -0
  143. data/lib/laser/types/types.rb +433 -0
  144. data/lib/laser/version.rb +14 -0
  145. data/lib/laser/warning.rb +149 -0
  146. data/lib/laser/warning_sets/default.yml +13 -0
  147. data/lib/laser/warnings/assignment_in_condition.rb +20 -0
  148. data/lib/laser/warnings/comment_spacing.rb +31 -0
  149. data/lib/laser/warnings/extra_blank_lines.rb +30 -0
  150. data/lib/laser/warnings/extra_whitespace.rb +16 -0
  151. data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
  152. data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
  153. data/lib/laser/warnings/line_length.rb +115 -0
  154. data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
  155. data/lib/laser/warnings/operator_spacing.rb +68 -0
  156. data/lib/laser/warnings/parens_on_declaration.rb +30 -0
  157. data/lib/laser/warnings/rescue_exception.rb +42 -0
  158. data/lib/laser/warnings/semicolon.rb +25 -0
  159. data/lib/laser/warnings/sexp_errors.rb +24 -0
  160. data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
  161. data/lib/laser/warnings/useless_double_quotes.rb +38 -0
  162. data/spec/analysis_specs/annotations_spec.rb +47 -0
  163. data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
  164. data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
  165. data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
  166. data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
  167. data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
  168. data/spec/analysis_specs/bindings_spec.rb +36 -0
  169. data/spec/analysis_specs/comment_spec.rb +93 -0
  170. data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
  171. data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
  172. data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
  173. data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
  174. data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
  175. data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
  176. data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
  177. data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
  178. data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
  179. data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
  180. data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
  181. data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
  182. data/spec/analysis_specs/error_spec.rb +30 -0
  183. data/spec/analysis_specs/laser_class_spec.rb +322 -0
  184. data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
  185. data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
  186. data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
  187. data/spec/analysis_specs/scope_spec.rb +126 -0
  188. data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
  189. data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
  190. data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
  191. data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
  192. data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
  193. data/spec/analysis_specs/sexp_spec.rb +167 -0
  194. data/spec/analysis_specs/spec_helper.rb +27 -0
  195. data/spec/analysis_specs/unused_methods_spec.rb +65 -0
  196. data/spec/analysis_specs/visitor_spec.rb +64 -0
  197. data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
  198. data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
  199. data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
  200. data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
  201. data/spec/annotation_parser_specs/spec_helper.rb +1 -0
  202. data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
  203. data/spec/laser_spec.rb +14 -0
  204. data/spec/rake_specs/spec_helper.rb +1 -0
  205. data/spec/rake_specs/task_spec.rb +67 -0
  206. data/spec/runner_spec.rb +207 -0
  207. data/spec/scanner_spec.rb +75 -0
  208. data/spec/spec_helper.rb +121 -0
  209. data/spec/standard_library/exceptions_spec.rb +19 -0
  210. data/spec/standard_library/globals_spec.rb +14 -0
  211. data/spec/standard_library/set_spec.rb +31 -0
  212. data/spec/standard_library/spec_helper.rb +1 -0
  213. data/spec/standard_library/standard_library_spec.rb +302 -0
  214. data/spec/support_specs/acts_as_struct_spec.rb +94 -0
  215. data/spec/support_specs/frequency_spec.rb +23 -0
  216. data/spec/support_specs/module_extensions_spec.rb +117 -0
  217. data/spec/support_specs/spec_helper.rb +1 -0
  218. data/spec/type_specs/spec_helper.rb +1 -0
  219. data/spec/type_specs/types_spec.rb +133 -0
  220. data/spec/warning_spec.rb +95 -0
  221. data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
  222. data/spec/warning_specs/comment_spacing_spec.rb +65 -0
  223. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  224. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  225. data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
  226. data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
  227. data/spec/warning_specs/line_length_spec.rb +173 -0
  228. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  229. data/spec/warning_specs/operator_spacing_spec.rb +104 -0
  230. data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
  231. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  232. data/spec/warning_specs/semicolon_spec.rb +58 -0
  233. data/spec/warning_specs/spec_helper.rb +1 -0
  234. data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
  235. data/status_reports/2010/12/2010-12-14.md +163 -0
  236. data/status_reports/2010/12/2010-12-23.md +298 -0
  237. data/status_reports/2010/12/2010-12-24.md +6 -0
  238. data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
  239. data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
  240. data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
  241. data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
  242. data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
  243. data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
  244. data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
  245. data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
  246. data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
  247. data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
  248. data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
  249. data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
  250. data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
  251. data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
  252. data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
  253. data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
  254. data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
  255. data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
  256. data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
  257. data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
  258. data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
  259. data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
  260. data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
  261. data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
  262. data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
  263. data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
  264. data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
  265. data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
  266. data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
  267. data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
  268. data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
  269. data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
  270. data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
  271. data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
  272. data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
  273. data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
  274. data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
  275. data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
  276. data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
  277. data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
  278. data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
  279. data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
  280. data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
  281. data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
  282. data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
  283. data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
  284. data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
  285. data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
  286. data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
  287. data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
  288. data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
  289. data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
  290. data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
  291. data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
  292. data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
  293. data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
  294. data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
  295. data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
  296. data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
  297. data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
  298. data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
  299. data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
  300. data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
  301. data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
  302. data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
  303. data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
  304. data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
  305. data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
  306. data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
  307. data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
  308. data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
  309. data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
  310. data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
  311. data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
  312. data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
  313. data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
  314. data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
  315. data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
  316. data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
  317. data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
  318. data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
  319. metadata +470 -0
@@ -0,0 +1,33 @@
1
+ require_relative '../spec_helper'
2
+
3
+ # Runs a shit-ton of expectations common among annotations. Since an annotaiton
4
+ # just adds an attribute to a Sexp, we have a very common set of examples o
5
+ # the form:
6
+ # tree[0].new_attribute.should == some_val
7
+ # tree[1][0].new_attribute.should == some_val
8
+ # ...
9
+ # tree[2][2].new_attribute.should == cool_inferred_val
10
+ # and so on. A ton of repetitiveness can be captured by using hashes in the form:
11
+ #
12
+ # {new_attribute: { some_val => [tree[1][0], tree[0], ...],
13
+ # { cool_inferred_val => [tree[2][2], ...] }}}
14
+ #
15
+ # Each attribute is a key in the toplevel hash, and each possible value is a key
16
+ # in the second-level hash. Technically this doesn't remove all duplication, but
17
+ # it's good.
18
+ def expectalot(expectation)
19
+ messages = expectation.keys
20
+ messages.each do |message|
21
+ examples = expectation[message]
22
+ examples.each do |expected_value, recipients|
23
+ recipients.each do |recipient|
24
+ begin
25
+ recipient.send(message).should == expected_value
26
+ rescue Exception => err
27
+ p "#{recipient.inspect}'s #{message} should be #{expected_value.inspect}"
28
+ raise err
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,113 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Analysis::ArgumentExpansion do
4
+ describe '#arity' do
5
+ it 'can figure out the arity of a simple method call with no arguments' do
6
+ tree = annotate_all('foo( )')[1][0][2]
7
+ ArgumentExpansion.new(tree).arity.should == (0..0)
8
+ end
9
+
10
+ it 'can figure out the arity of a simple method call' do
11
+ tree = annotate_all('foo(1, 2, 3)')[1][0][2]
12
+ ArgumentExpansion.new(tree).arity.should == (3..3)
13
+ end
14
+
15
+ it 'does not count block arguments in arity' do
16
+ tree = annotate_all('foo(1, 2, 3, &d())')[1][0][2]
17
+ ArgumentExpansion.new(tree).arity.should == (3..3)
18
+ end
19
+
20
+ it 'has an infinite maximum arity in the presence of un-computable splats' do
21
+ tree = annotate_all('foo(1, 2, 3, *foobar())')[1][0][2]
22
+ ArgumentExpansion.new(tree).arity.should == (3..Float::INFINITY)
23
+ end
24
+
25
+ it 'count arguments after splats' do
26
+ tree = annotate_all('foo(1, 2, 3, *foobar(), 4, 5)')[1][0][2]
27
+ ArgumentExpansion.new(tree).arity.should == (5..Float::INFINITY)
28
+ end
29
+
30
+ it 'splats constant arguments to precise arity' do
31
+ tree = annotate_all('foo(1, 2, 3, *[:a, :b, :c], 4, 5)')[1][0][2]
32
+ ArgumentExpansion.new(tree).arity.should == (8..8)
33
+ end
34
+
35
+ it 'splats constant range arguments to precise arity' do
36
+ tree = annotate_all('foo(1, 2, 3, *(2...10), 4, 5)')[1][0][2]
37
+ ArgumentExpansion.new(tree).arity.should == (13..13)
38
+ end
39
+ end
40
+
41
+ describe '#empty?' do
42
+ it 'returns true when no args are being passed' do
43
+ tree = annotate_all('foo( )')[1][0][2]
44
+ ArgumentExpansion.new(tree).should be_empty
45
+ end
46
+
47
+ it 'returns false when args are being passed' do
48
+ tree = annotate_all('foo( 2 )')[1][0][2]
49
+ ArgumentExpansion.new(tree).should_not be_empty
50
+ end
51
+ end
52
+
53
+ describe '#has_block?' do
54
+ it 'returns false with no arguments given' do
55
+ tree = annotate_all('foo()')[1][0][2]
56
+ ArgumentExpansion.new(tree).has_block?.should be false
57
+ end
58
+
59
+ it 'returns true if there is an explicit block argument' do
60
+ tree = annotate_all('foo(1, 2, 3, &d)')[1][0][2]
61
+ ArgumentExpansion.new(tree).has_block?.should be_true
62
+ end
63
+
64
+ it 'returns false if there is an explicit block argument' do
65
+ tree = annotate_all('foo(1, 2, 3, *foobar())')[1][0][2]
66
+ ArgumentExpansion.new(tree).has_block?.should be false
67
+ end
68
+ end
69
+
70
+ describe '#is_constant?' do
71
+ it 'returns true for no params' do
72
+ tree = annotate_all('foo()')[1][0][2]
73
+ ArgumentExpansion.new(tree).is_constant?.should be_true
74
+ end
75
+ it 'returns true if all constituent arguments are constant' do
76
+ tree = annotate_all('foo(1, 2, 3)')[1][0][2]
77
+ ArgumentExpansion.new(tree).is_constant?.should be_true
78
+ end
79
+
80
+ it 'returns true if all constituent arguments are constant in the presenece of splats' do
81
+ tree = annotate_all('foo(1, 2, *[1, 2], 4, *("a"..."d"))')[1][0][2]
82
+ ArgumentExpansion.new(tree).is_constant?.should be_true
83
+ end
84
+
85
+ it 'returns false in the presence of non-constant arguments' do
86
+ tree = annotate_all('foo(1, foobar(), 3)')[1][0][2]
87
+ ArgumentExpansion.new(tree).is_constant?.should be_false
88
+ end
89
+ end
90
+
91
+ describe '#constant_values' do
92
+ it 'returns true for no params' do
93
+ tree = annotate_all('foo()')[1][0][2]
94
+ ArgumentExpansion.new(tree).constant_values.should == []
95
+ end
96
+ it 'returns true if all constituent arguments are constant' do
97
+ tree = annotate_all('foo(1, 2, 3)')[1][0][2]
98
+ ArgumentExpansion.new(tree).constant_values.should == [1, 2, 3]
99
+ end
100
+
101
+ it 'returns true if all constituent arguments are constant in the presence of splats' do
102
+ tree = annotate_all('foo(1, 2, *[1, 2], 4, *("a"..."d"))')[1][0][2]
103
+ ArgumentExpansion.new(tree).constant_values.should == [1, 2, 1, 2, 4, 'a', 'b', 'c']
104
+ end
105
+
106
+ it 'expands a splatted literal array' do
107
+ tree = annotate_all('foobar *[:a, :b]')[1][0][2]
108
+ expansion = ArgumentExpansion.new(tree)
109
+ expansion.is_constant?.should be_true
110
+ expansion.constant_values.should == [:a, :b]
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,36 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Analysis::Bindings::Base do
4
+ describe '#initialize' do
5
+ it 'has a simple struct-like initializer' do
6
+ name, value = many_mocks(2)
7
+ sym = Analysis::Bindings::Base.new(name, value)
8
+ sym.name.should == name
9
+ sym.value.should == value
10
+ end
11
+ end
12
+
13
+ describe '#<=>' do
14
+ it 'should compare based on name alone' do
15
+ value = mock
16
+ sym1 = Analysis::Bindings::Base.new('hello', value)
17
+ sym2 = Analysis::Bindings::Base.new('helga', value)
18
+ sym1.should > sym2
19
+ end
20
+ end
21
+ end
22
+
23
+ describe Analysis::Bindings::ConstantBinding do
24
+ describe '#bind!' do
25
+ it 'should raise on a rebinding when not forcing' do
26
+ sym = Analysis::Bindings::ConstantBinding.new('hi', 1)
27
+ expect { sym.bind!(2) }.to raise_error(TypeError)
28
+ end
29
+
30
+ it 'should not raise on a rebinding when forcing' do
31
+ sym = Analysis::Bindings::ConstantBinding.new('hi', 3)
32
+ sym.bind!(4, true)
33
+ sym.value.should == 4
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,93 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Laser::Comment do
4
+ before do
5
+ body = <<-EOF
6
+ ##
7
+ # Returns a repository object for the given path. Should respond to the standard repository
8
+ # API to the best of its ability, and raise a CapabilityError if asked to do something it
9
+ # cannot do from the API.
10
+ #
11
+ # @param [AmpConfig] config the configuration of the current environment, loaded from
12
+ # appropriate configuration files
13
+ # @param [String] path the path/URL in which to open the repository.
14
+ # @param [Boolean] create should a repository be created in the given directory/URL?
15
+ # @return [AbstractLocalRepository] the repository for the given URL
16
+ # @example
17
+ # Repo.pick('abc/def') do |foo|
18
+ # File.open(foo + '/.hg/hgrc')
19
+ # end
20
+ EOF
21
+ @comment = Laser::Comment.new(body, 2, 4)
22
+ normal_annotated_body = <<-EOF
23
+ ##
24
+ # Returns a repository object for the given path. Should respond to the standard repository
25
+ # cannot do from the API.
26
+ #
27
+ # config: AmpConfig
28
+ # path: String=
29
+ # create: TrueClass | FalseClass
30
+ # return: AbstractLocalRepository
31
+ # @example
32
+ # Repo.pick('abc/def') do |foo|
33
+ # File.open(foo + '/.hg/hgrc')
34
+ # end
35
+ EOF
36
+ @annotated_comment = Laser::Comment.new(normal_annotated_body, 8, 12)
37
+ end
38
+
39
+ describe '#location' do
40
+ it 'packs up the line and column' do
41
+ @comment.location.should == [2, 4]
42
+ end
43
+ end
44
+
45
+ describe '#features' do
46
+ it 'should extract features based on whether line breaks are followed by many spaces' do
47
+ @comment.features.should == [
48
+ 'Returns a repository object for the given path. Should respond to the standard repository',
49
+ 'API to the best of its ability, and raise a CapabilityError if asked to do something it',
50
+ 'cannot do from the API.',
51
+ "@param [AmpConfig] config the configuration of the current environment, loaded from\n"+
52
+ " appropriate configuration files",
53
+ '@param [String] path the path/URL in which to open the repository.',
54
+ '@param [Boolean] create should a repository be created in the given directory/URL?',
55
+ '@return [AbstractLocalRepository] the repository for the given URL',
56
+ "@example\n"+
57
+ " Repo.pick('abc/def') do |foo|\n"+
58
+ " File.open(foo + '/.hg/hgrc')\n"+
59
+ " end"
60
+ ]
61
+ end
62
+ end
63
+
64
+ describe '#annotations' do
65
+ it 'should extract annotations and parse them' do
66
+ notes = @annotated_comment.annotations
67
+ parts = notes.map(&:name).zip notes.map(&:type)
68
+ parts.should == [
69
+ ['config', Types::ClassType.new('AmpConfig', :covariant)],
70
+ ['path', Types::ClassType.new('String', :invariant)],
71
+ ['create', Types::UnionType.new([
72
+ Types::ClassType.new('TrueClass', :covariant),
73
+ Types::ClassType.new('FalseClass', :covariant)])],
74
+ ['return', Types::ClassType.new('AbstractLocalRepository', :covariant)]
75
+ ]
76
+ end
77
+ end
78
+
79
+ describe '#annotation_map' do
80
+ it 'should extract annotations and convert them to a hash keyed by name' do
81
+ map = @annotated_comment.annotation_map.to_a
82
+ parts = map.map { |name, note| [name, note[0].name, note[0].type] }
83
+ parts.should == [
84
+ ['config', 'config', Types::ClassType.new('AmpConfig', :covariant)],
85
+ ['path', 'path', Types::ClassType.new('String', :invariant)],
86
+ ['create', 'create', Types::UnionType.new([
87
+ Types::ClassType.new('TrueClass', :covariant),
88
+ Types::ClassType.new('FalseClass', :covariant)])],
89
+ ['return', 'return', Types::ClassType.new('AbstractLocalRepository', :covariant)]
90
+ ]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,111 @@
1
+ require 'set'
2
+ require_relative 'spec_helper'
3
+
4
+ describe ControlFlow::Instruction do
5
+ describe '#explicit_targets' do
6
+ before do
7
+ @temp = Bindings::TemporaryBinding.new('%t1', nil)
8
+ @call_target = Bindings::TemporaryBinding.new('%t2', nil)
9
+ @ary = Bindings::TemporaryBinding.new('%t3', nil)
10
+ end
11
+
12
+ it 'should return an empty set for a return node' do
13
+ ControlFlow::Instruction.new([:return, 1, 2]).
14
+ explicit_targets.should == ::Set[]
15
+ end
16
+
17
+ it 'should return an empty set for a jump node' do
18
+ ControlFlow::Instruction.new([:jump, 'B1']).
19
+ explicit_targets.should == ::Set[]
20
+ end
21
+
22
+ it 'should return an empty set for a branch node' do
23
+ ControlFlow::Instruction.new([:branch, 't1', 'b2', 'b3']).
24
+ explicit_targets.should == ::Set[]
25
+ end
26
+
27
+ it 'should return the target for an assign instruction' do
28
+ ControlFlow::Instruction.new([:assign, @temp, 2]).
29
+ explicit_targets.should == ::Set[@temp]
30
+ end
31
+
32
+ it 'should return the target for a call instruction' do
33
+ ControlFlow::Instruction.new([:call, @call_target, @temp, 'to_i', :block => false]).
34
+ explicit_targets.should == ::Set[@call_target]
35
+ end
36
+
37
+ it 'should return the target for a call_vararg instruction' do
38
+ ControlFlow::Instruction.new([:call_vararg, @call_target, @temp, 'to_i', @ary, :block => false]).
39
+ explicit_targets.should == ::Set[@call_target]
40
+ end
41
+
42
+ it 'should return the target for a super instruction' do
43
+ ControlFlow::Instruction.new([:super, @call_target, :block => false]).
44
+ explicit_targets.should == ::Set[@call_target]
45
+ end
46
+
47
+ it 'should return the target for a super_vararg instruction' do
48
+ ControlFlow::Instruction.new([:super_vararg, @call_target, @ary, :block => false]).
49
+ explicit_targets.should == ::Set[@call_target]
50
+ end
51
+
52
+ it 'should return the target for a lambda instruction' do
53
+ ControlFlow::Instruction.new([:lambda, @temp, 'B2']).
54
+ explicit_targets.should == ::Set[@temp]
55
+ end
56
+ end
57
+
58
+ describe '#operands' do
59
+ before(:all) do
60
+ @temp = Bindings::TemporaryBinding.new('%t1', nil)
61
+ @call_target = Bindings::TemporaryBinding.new('%t2', nil)
62
+ @ary = Bindings::TemporaryBinding.new('%t3', nil)
63
+ @temp_2 = Bindings::TemporaryBinding.new('%t4', nil)
64
+ end
65
+
66
+ it 'should return a set with the returned value for a return node' do
67
+ ControlFlow::Instruction.new([:return, @temp]).
68
+ operands.should == [@temp]
69
+ end
70
+
71
+ it 'should return an empty set for a jump node' do
72
+ ControlFlow::Instruction.new([:jump, 'B1']).
73
+ operands.should == []
74
+ end
75
+
76
+ it 'should return a set with the branched-on value for a branch node' do
77
+ ControlFlow::Instruction.new([:branch, @temp, 'b2', 'b3']).
78
+ operands.should == [@temp]
79
+ end
80
+
81
+ it 'should return the value temporary for an assign instruction' do
82
+ ControlFlow::Instruction.new([:assign, @temp, @ary]).
83
+ operands.should == [@ary]
84
+ end
85
+
86
+ it 'should return the receiver and arguments for a call instruction' do
87
+ ControlFlow::Instruction.new([:call, @call_target, @temp, 'to_i', @temp_2, :block => false]).
88
+ operands.should == [@temp, @temp_2]
89
+ end
90
+
91
+ it 'should return the receiver and arguments for a call_vararg instruction' do
92
+ ControlFlow::Instruction.new([:call_vararg, @call_target, @temp, 'to_i', @ary, :block => false]).
93
+ operands.should == [@temp, @ary]
94
+ end
95
+
96
+ it 'should return the arguments for a super instruction' do
97
+ ControlFlow::Instruction.new([:super, @call_target, @temp_2, :block => false]).
98
+ operands.should == [@temp_2]
99
+ end
100
+
101
+ it 'should return the arguments for a super_vararg instruction' do
102
+ ControlFlow::Instruction.new([:super_vararg, @call_target, @ary, :block => false]).
103
+ operands.should == [@ary]
104
+ end
105
+
106
+ it 'should return the empty set for a lambda instruction' do
107
+ ControlFlow::Instruction.new([:lambda, @temp, 'B2']).
108
+ operands.should == []
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,560 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ControlFlow::ConstantPropagation do
4
+ it 'should propagate simple constants along linear code' do
5
+ g = cfg_method <<-EOF
6
+ def foo(x)
7
+ z = 1024
8
+ y = z
9
+ w = y
10
+ end
11
+ EOF
12
+ g.should have_constant('w').with_value(1024)
13
+ end
14
+
15
+ it 'should infer constants due to semantics of mismatched parallel assignments' do
16
+ g = cfg_method <<-EOF
17
+ def foo(x)
18
+ a, b, c = x, 10
19
+ end
20
+ EOF
21
+ g.should have_constant('b').with_value(10)
22
+ g.should have_constant('c').with_value(nil)
23
+ g.should_not have_constant('a')
24
+ end
25
+
26
+ it 'should infer constants due to semantics of 1-to-N parallel assignment' do
27
+ g = cfg_method <<-EOF
28
+ def foo(x)
29
+ a = 1, (2 ** 10), 3
30
+ end
31
+ EOF
32
+ g.should have_constant('a').with_value([1, 1024, 3])
33
+ end
34
+
35
+ it 'should infer constants due to semantics of 1-to-N parallel assignment with splats' do
36
+ g = cfg_method <<-EOF
37
+ def foo(x)
38
+ a = 1, (2 ** 10), 3, *(1..3), 'hi', :a
39
+ end
40
+ EOF
41
+ g.should have_constant('a').with_value([1, 1024, 3, 1, 2, 3, 'hi', :a])
42
+ end
43
+
44
+ it 'should infer constants due to semantics of N-to-1 parallel assignment' do
45
+ g = cfg_method <<-EOF
46
+ def foo(x)
47
+ a, b, c = [1, 2, 3]
48
+ end
49
+ EOF
50
+ g.should have_constant('a').with_value(1)
51
+ g.should have_constant('b').with_value(2)
52
+ g.should have_constant('c').with_value(3)
53
+ end
54
+
55
+ it 'should infer constants due to semantics of mismatched N-to-1 parallel assignment and Array indexing' do
56
+ g = cfg_method <<-EOF
57
+ def foo(x)
58
+ a, b, c, d = [1, 2, 3]
59
+ end
60
+ EOF
61
+ g.should have_constant('a').with_value(1)
62
+ g.should have_constant('b').with_value(2)
63
+ g.should have_constant('c').with_value(3)
64
+ g.should have_constant('d').with_value(nil)
65
+ end
66
+
67
+ it 'should infer constants with LHS star and no RHS star' do
68
+ g = cfg_method <<-EOF
69
+ def foo(x)
70
+ a, *b, d = 1, 2, 3, 4
71
+ end
72
+ EOF
73
+ g.should have_constant('a').with_value(1)
74
+ g.should have_constant('b').with_value([2, 3])
75
+ g.should have_constant('d').with_value(4)
76
+ end
77
+
78
+ it 'should infer constants with discarded LHS star and no RHS star' do
79
+ g = cfg_method <<-EOF
80
+ def foo(x)
81
+ a, *, d = 1, 2, 3, :a, 'hi', gets, 4
82
+ end
83
+ EOF
84
+ g.should have_constant('a').with_value(1)
85
+ g.should have_constant('d').with_value(4)
86
+ end
87
+
88
+ it 'should infer constants with LHS star and no RHS star and mismatched sizes' do
89
+ g = cfg_method <<-EOF
90
+ def foo(x)
91
+ a, *b, d, e = 1, 2
92
+ end
93
+ EOF
94
+ g.should have_constant('a').with_value(1)
95
+ g.should have_constant('b').with_value([])
96
+ g.should have_constant('d').with_value(2)
97
+ g.should have_constant('e').with_value(nil)
98
+ end
99
+
100
+ it 'should infer constants with LHS star and no RHS star and mismatched sizes: part two' do
101
+ g = cfg_method <<-EOF
102
+ def foo(x)
103
+ a, b, c, *d = 1, 2
104
+ end
105
+ EOF
106
+ g.should have_constant('a').with_value(1)
107
+ g.should have_constant('b').with_value(2)
108
+ g.should have_constant('c').with_value(nil)
109
+ g.should have_constant('d').with_value([])
110
+ end
111
+
112
+ context 'with implicitly-splatted single RHS' do
113
+ it 'should infer constants with LHS star and no RHS star' do
114
+ g = cfg_method <<-EOF
115
+ def foo(x)
116
+ a, *b, d = [1, 2, 3, 4]
117
+ x = a
118
+ y = b
119
+ z = d
120
+ end
121
+ EOF
122
+ g.should have_constant('x').with_value(1)
123
+ g.should have_constant('y').with_value([2, 3])
124
+ g.should have_constant('z').with_value(4)
125
+ end
126
+
127
+ it 'should infer constants with discarded LHS star and no RHS star' do
128
+ g = cfg_method <<-EOF
129
+ def foo(x)
130
+ a, *, d = [1, 2, 3, :a, 'hi', {}, 4]
131
+ x = a
132
+ y = d
133
+ end
134
+ EOF
135
+ g.should have_constant('x').with_value(1)
136
+ g.should have_constant('y').with_value(4)
137
+ end
138
+
139
+ it 'should infer constants with LHS star and no RHS star and mismatched sizes' do
140
+ g = cfg_method <<-EOF
141
+ def foo(x)
142
+ a, *b, d, e = [1, 2]
143
+ rest = b
144
+ x = d
145
+ y = e
146
+ end
147
+ EOF
148
+ g.should have_constant('a').with_value(1)
149
+ g.should have_constant('rest').with_value([])
150
+ g.should have_constant('x').with_value(2)
151
+ g.should have_constant('y').with_value(nil)
152
+ end
153
+
154
+ it 'should infer constants with LHS star and no RHS star and mismatched sizes: part two' do
155
+ g = cfg_method <<-EOF
156
+ def foo(x)
157
+ a, b, c, *d = [1, 2]
158
+ rest = d
159
+ end
160
+ EOF
161
+ g.should have_constant('a').with_value(1)
162
+ g.should have_constant('b').with_value(2)
163
+ g.should have_constant('c').with_value(nil)
164
+ g.should have_constant('rest').with_value([])
165
+ end
166
+ end
167
+
168
+ it 'should infer constants with an RHS star' do
169
+ g = cfg_method <<-EOF
170
+ def foo(x)
171
+ a, b, c, d, e, f, g, h = *[2, 3, 4], :a, *[5], *['hi'], 9, 10, 11, 12
172
+ end
173
+ EOF
174
+ g.should have_constant('a').with_value(2)
175
+ g.should have_constant('b').with_value(3)
176
+ g.should have_constant('c').with_value(4)
177
+ g.should have_constant('d').with_value(:a)
178
+ g.should have_constant('e').with_value(5)
179
+ g.should have_constant('f').with_value('hi')
180
+ g.should have_constant('g').with_value(9)
181
+ g.should have_constant('h').with_value(10)
182
+ end
183
+
184
+ it 'should infer constants with an RHS star and unmet lhs vars' do
185
+ g = cfg_method <<-EOF
186
+ def foo(x)
187
+ a, b, c, d, e, f, g, h = *[2, 3, 4], :a
188
+ end
189
+ EOF
190
+ g.should have_constant('a').with_value(2)
191
+ g.should have_constant('b').with_value(3)
192
+ g.should have_constant('c').with_value(4)
193
+ g.should have_constant('d').with_value(:a)
194
+ g.should have_constant('e').with_value(nil)
195
+ g.should have_constant('f').with_value(nil)
196
+ g.should have_constant('g').with_value(nil)
197
+ g.should have_constant('h').with_value(nil)
198
+ end
199
+
200
+ it 'should infer constants with LHS and RHS stars' do
201
+ g = cfg_method <<-EOF
202
+ def foo(x)
203
+ a, b, *rest, f, g, h = *[2, 3, 4], :a, *[5], *['hi'], 9, 10, 11, 12
204
+ end
205
+ EOF
206
+ g.should have_constant('a').with_value(2)
207
+ g.should have_constant('b').with_value(3)
208
+ g.should have_constant('rest').with_value([4, :a, 5, 'hi', 9])
209
+ g.should have_constant('f').with_value(10)
210
+ g.should have_constant('g').with_value(11)
211
+ g.should have_constant('h').with_value(12)
212
+ end
213
+
214
+ it 'should propagate when the same variable is assigned to the same constant in branches' do
215
+ g = cfg_method <<-EOF
216
+ def foo(x)
217
+ if gets.size > 0
218
+ y = 20
219
+ else
220
+ y = 20
221
+ end
222
+ z = y
223
+ end
224
+ EOF
225
+ g.should have_constant('z').with_value(20)
226
+ end
227
+
228
+ it 'should propagate manipulation of hashes' do
229
+ g = cfg_method <<-EOF
230
+ def foo(x)
231
+ z = {a: 3, 'd' => 4.5}
232
+ j = z[:a]
233
+ arr = z.values
234
+ end
235
+ EOF
236
+ g.should have_constant('j').with_value(3)
237
+ g.should have_constant('arr').with_value([3, 4.5])
238
+ end
239
+
240
+ it 'should not propagate when the same variable is assigned to distinct constants in branches' do
241
+ g = cfg_method <<-EOF
242
+ def foo(x)
243
+ if gets.size > 0
244
+ y = 20
245
+ else
246
+ y = 30
247
+ end
248
+ z = y
249
+ end
250
+ EOF
251
+ g.should_not have_constant('z')
252
+ end
253
+
254
+ it 'should ignore branches on false' do
255
+ g = cfg_method <<-EOF
256
+ def foo(x)
257
+ if false
258
+ y = 40
259
+ else
260
+ y = 30
261
+ end
262
+ z = y
263
+ end
264
+ EOF
265
+ g.should have_constant('z').with_value(30)
266
+ end
267
+
268
+ it 'should ignore else branches on true' do
269
+ g = cfg_method <<-EOF
270
+ def foo(x)
271
+ if true
272
+ y = 40
273
+ else
274
+ y = 30
275
+ end
276
+ z = y
277
+ end
278
+ EOF
279
+ g.should have_constant('z').with_value(40)
280
+ end
281
+
282
+ it 'should ignore branches on constant variables' do
283
+ g = cfg_method <<-EOF
284
+ def foo(x)
285
+ a = true ? 30 : false
286
+ if a
287
+ y = 40
288
+ else
289
+ y = 30
290
+ end
291
+ z = y
292
+ end
293
+ EOF
294
+ g.should have_constant('z').with_value(40)
295
+ end
296
+
297
+ it 'should ignore branches on fixnum equality' do
298
+ g = cfg_method <<-EOF
299
+ def foo(x)
300
+ a = true ? 30 : false
301
+ if a == 30
302
+ y = 40
303
+ else
304
+ y = 30
305
+ end
306
+ z = y
307
+ end
308
+ EOF
309
+ g.should have_constant('z').with_value(40)
310
+ end
311
+
312
+ it 'should ignore branches on non-constants whose types are never be nil or false' do
313
+ g = cfg_method <<-EOF
314
+ def foo(x)
315
+ a = x.nil? ? 30 : 'hello'
316
+ b = a * 2
317
+ if b
318
+ y = 40
319
+ else
320
+ y = 30
321
+ end
322
+ z = y
323
+ end
324
+ EOF
325
+ g.should have_constant('z').with_value(40)
326
+ end
327
+
328
+ it 'should calculate bignum arithmetic' do
329
+ g = cfg_method <<-EOF
330
+ def foo(x)
331
+ a = 3 * (1 << 3)
332
+ b = a ** a
333
+ c = b - a
334
+ end
335
+ EOF
336
+ g.should have_constant('c').with_value(1333735776850284124449081472843752)
337
+ end
338
+
339
+ it 'should handle string constants' do
340
+ g = cfg_method <<-EOF
341
+ def foo(x)
342
+ y = 'hello' * 3
343
+ if y == 'hellohellohello'
344
+ puts gets
345
+ z = 3
346
+ else
347
+ z = 10
348
+ end
349
+ a = z
350
+ end
351
+ EOF
352
+ g.should have_constant('a').with_value(3)
353
+ end
354
+
355
+ it 'should calculate 0 * (varying numeric) = 0' do
356
+ g = cfg_method <<-EOF
357
+ def foo(x)
358
+ if gets.size > 0
359
+ a = 5
360
+ else
361
+ a = 10.11
362
+ end
363
+ b = 0 * a
364
+ c = a * 0
365
+ end
366
+ EOF
367
+ g.should have_constant('b').with_value(0)
368
+ g.should have_constant('c').with_value(0)
369
+ end
370
+
371
+ it 'should calculate (varying string) * 0 = ""' do
372
+ g = cfg_method <<-EOF
373
+ def foo(x)
374
+ if gets.size > 0
375
+ a = 'hello'
376
+ else
377
+ a = 'world'
378
+ end
379
+ c = a * 0
380
+ end
381
+ EOF
382
+ g.should have_constant('c').with_value('')
383
+ end
384
+
385
+ it 'should calculate (varying array) * 0 = []' do
386
+ g = cfg_method <<-EOF
387
+ def foo(x)
388
+ if gets.size > 0
389
+ a = [1, 'hello']
390
+ else
391
+ a = [2, 'world', 'thing']
392
+ end
393
+ c = a * 0
394
+ end
395
+ EOF
396
+ g.should have_constant('c').with_value([])
397
+ end
398
+
399
+ it 'should calculate 0 * (varying numeric | string) = varying' do
400
+ g = cfg_method <<-EOF
401
+ def foo(x)
402
+ if gets.size > 0
403
+ a = 5
404
+ else
405
+ a = 'hello'
406
+ end
407
+ b = 0 * a
408
+ c = a * 0
409
+ end
410
+ EOF
411
+ g.should_not have_constant('b')
412
+ g.should_not have_constant('c')
413
+ end
414
+
415
+ it 'should calculate (varying numeric) ** 0 = 1' do
416
+ g = cfg_method <<-EOF
417
+ def foo(x)
418
+ if gets.size > 0
419
+ a = 5.93
420
+ else
421
+ a = 10
422
+ end
423
+ c = a ** 0
424
+ end
425
+ EOF
426
+ g.should have_constant('c').with_value(1)
427
+ end
428
+
429
+ it 'should calculate (varying numeric | string) ** 0 = varying' do
430
+ g = cfg_method <<-EOF
431
+ def foo(x)
432
+ if gets.size > 0
433
+ a = 5
434
+ else
435
+ a = 'hello'
436
+ end
437
+ c = a ** 0
438
+ end
439
+ EOF
440
+ g.should_not have_constant('c')
441
+ end
442
+
443
+ it 'should calculate 1 ** (varying numeric) = 1' do
444
+ g = cfg_method <<-EOF
445
+ def foo(x)
446
+ if gets.size > 0
447
+ a = 5
448
+ else
449
+ a = 10.2
450
+ end
451
+ c = 1 ** a
452
+ end
453
+ EOF
454
+ g.should have_constant('c').with_value(1)
455
+ end
456
+
457
+ it 'should calculate 1 ** (varying numeric | string) = varying' do
458
+ g = cfg_method <<-EOF
459
+ def foo(x)
460
+ if gets.size > 0
461
+ a = 5
462
+ else
463
+ a = 'hello'
464
+ end
465
+ c = 1 ** a
466
+ end
467
+ EOF
468
+ g.should_not have_constant('c')
469
+ end
470
+
471
+ it 'should infer that assignments after a guaranteed raise do not affect CP' do
472
+ g = cfg_method <<-EOF
473
+ def foo(x)
474
+ if gets.size > 0
475
+ a = 5
476
+ else
477
+ raise 'arrrrrrr'
478
+ a = 10.2
479
+ end
480
+ c = a
481
+ end
482
+ EOF
483
+ g.should have_constant('c').with_value(5)
484
+ end
485
+
486
+ it 'should infer that assignments after a guaranteed raise (by CP simulation) do not affect CP' do
487
+ g = cfg_method <<-EOF
488
+ def foo(x)
489
+ if gets.size > 0
490
+ a = 5
491
+ else
492
+ a = 5 / 0
493
+ end
494
+ c = a
495
+ end
496
+ EOF
497
+ g.should have_constant('c').with_value(5)
498
+ g.return_type.should equal_type Types::FIXNUM
499
+ end
500
+
501
+ it 'should always simulate annotated-pure methods' do
502
+ g = cfg <<-EOF
503
+ module CPSim1
504
+ # pure: true
505
+ def self.make(x, y)
506
+ {x: x, y: y}
507
+ end
508
+ end
509
+ EOF
510
+ g2 = cfg_method <<-EOF
511
+ def foo(x)
512
+ made = CPSim1.make(3, 'foo')
513
+ z1 = made[:x]
514
+ z2 = made[:y]
515
+ end
516
+ EOF
517
+ g2.should have_constant('z1').with_value(3)
518
+ g2.should have_constant('z2').with_value('foo')
519
+ g2.return_type.should equal_type Types::STRING
520
+ ClassRegistry['CPSim1'].singleton_class.instance_method(:make).
521
+ return_type_for_types(Utilities.type_for(ClassRegistry['CPSim1']),
522
+ [Types::FIXNUM, Types::STRING], Types::NILCLASS).should equal_type(Types::UnionType.new([Types::HASH]))
523
+ end
524
+
525
+ it 'should handle the tricky x = y unless defined? x case' do
526
+ g = cfg_method <<-EOF
527
+ def foo
528
+ y = 5 unless defined? y
529
+ z = y
530
+ end
531
+ EOF
532
+ g.should have_constant('z').with_value(nil)
533
+ end
534
+
535
+ it 'should handle a basic positive defined?(Const) case' do
536
+ g = cfg <<-EOF
537
+ module CP2
538
+ end
539
+ CP3 = 10 if defined?(CP2)
540
+ EOF
541
+ ClassRegistry['Object'].const_get('CP3').should == 10
542
+ end
543
+
544
+ it 'should handle a basic negative defined?(Const) case' do
545
+ g = cfg <<-EOF
546
+ CP4 = 10 unless defined?(CPNone)
547
+ EOF
548
+ ClassRegistry['Object'].const_get('CP4').should == 10
549
+ end
550
+
551
+ it 'should handle blocks used in constant propagation' do
552
+ g = cfg_method <<-EOF
553
+ def foo_blockitized
554
+ z = %w(a b c).map { |y| y * 2 }
555
+ 10
556
+ end
557
+ EOF
558
+ g.should have_constant('z').with_value(['aa', 'bb', 'cc'])
559
+ end
560
+ end