[
  {
    "path": ".gitignore",
    "content": "/build/\nout/\n*/build/\n.gradle\n\n.idea/\n\n**/*.iml\n**/.rakeTasks\narg_scanner/arg_scanner.iml\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: ruby\ndist: trusty\nos:\n  - linux\n#  - osx\n\nrvm:\n  - 2.3.3\n  - 2.4.2\n  - ruby-head\n\nmatrix:\n  fast_finish: true\n  allow_failures:\n    - rvm: ruby-head\n\nservices:\n  - mysql\n\ncache:\n  directories:\n    - $HOME/.gradle/caches/\n    - $HOME/.gradle/wrapper/\n\nbefore_install:\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then brew update       ; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then brew install mysql; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then mysql.server start; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then mysql -u root -e \"CREATE USER 'travis'@'127.0.0.1' IDENTIFIED BY '';\"; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then mysql -u root -e \"FLUSH PRIVILEGES;\"; fi\n  - mysql -u root -e 'CREATE DATABASE ruby_type_contracts;'\n  - mysql -u root -e 'GRANT ALL ON ruby_type_contracts.* TO 'travis'@'127.0.0.1';'\n  - cd arg_scanner\n\nscript:\n  - gem install rake\n  - rake test\n  - rake install\n  - cd ..\n  - travis_wait 40 ./gradlew tasks\n  - ./gradlew -Dmysql.user.name=travis -Dmysql.user.password=\"\"  test"
  },
  {
    "path": "FEATURES.md",
    "content": "# ruby-type-inference features\n\nThis doc contains `ruby-type-inference` features which can be useful \nfor you after running your ruby program under type tracker:\n\n![Run with type tracker](screenshots/run_with_type_tracker.png)\n\n## Type providing for method parameters\n\n![Parameter type providing](screenshots/parameter_type_providing.png)\n\n\n## Type providing for return value\n\n![Return type providing](screenshots/return_type_providing.png)\n\n## Side notes\n\nAs now RubyMine has more information about types it can provide \nmore reliable code completion, code analysis and other code insight features\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2016-2017 JetBrains s.r.o.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "Automated Type Contracts Generation [![JetBrains incubator project](http://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![Build Status](https://travis-ci.org/JetBrains/ruby-type-inference.svg?branch=master)](https://travis-ci.org/JetBrains/ruby-type-inference)\n===================================\n\n`ruby-type-inference` project is a completely new approach to\ntackle the problems of Ruby dynamic nature and provide more reliable\nsymbol resolution and type inference. It collects some run time data\nto build type contracts for the methods.\n\nEvery time a method is being called, some arguments of\nparticular types are being passed to it. Type Tracker collects\nall such argument combinations and then builds a special contract\nwhich satisfies all encountered argument type tuples. \n\nThe approach has its own pros and cons:\n* The obtained contracts utilize real-world usages of code of\n  any complexity so it provides true results even if a method\n  utilizes dynamic Ruby features heavily.\n* The completeness of the contracts obtained for a method highly\n  depends on the coverage of that method, including its callees.\n  That implies the need to merge the data obtained from the\n  different sources (e.g. different projects using the same gem).\n  \nThis implementation addresses the stated coverage problem by providing\nthe possibility to merge any type contracts at any time.\n     \n## Usage\n\nFor simple usage you need to install the [Ruby Dynamic Code Insight](https://plugins.jetbrains.com/plugin/10227-ruby-dynamic-code-insight) \nplugin for RubyMine. Then this plugin will require the [arg_scanner](https://rubygems.org/gems/arg_scanner) gem to be installed.\nSee [arg_scanner installation instruction](arg_scanner/README.md#installation) if you have problems while installation. \n\nAfter that, you will have the possibility to run your programs under type tracker:\n\n![Run with type tracker](screenshots/run_with_type_tracker.png)\n\nOr you can run your programs in terminal via the `rubymine-type-tracker` binary (But you have to keep your project opened \nin RubyMine). E.g.:\n```\nrubymine-type-tracker bin/rails server\n```\n\nThe `rubymine-type-tracker` binary is included into the [arg_scanner](https://rubygems.org/gems/arg_scanner) gem.\n\nSee [FEATURES.md](FEATURES.md) for understanding what benefits you will have after running your program under type tracker.\n     \n## Architecture\n \n* **arg_scanner** is a gem with a native extension to attach to \n  ruby processes and trace and intercept all method calls to log \n  type-wise data flow in runtime.\n  \n  See [`arg_scanner`] documentation for details on usage.\n\n* The [**type contract processor**](contract-creator) server listens for\n  incoming type data (from `arg_scanner`) and processes it to a compact format.\n  \n  The data stored may be used later for better code analysis and also\n  can be shared with other users.\n\n* Code analysis clients (a RubyMine/IJ+Ruby [plugin](ide-plugin)) use the contract data\n  to provide features for the users such as code completion, better resolution, etc.\n\n* (_todo_) Signature server receives contracts anonymously from the users and provides\n  a compiled contract collections for popular gems.\n\n## Running project from sources\n\n#### Prerequisites\n\nThe [`arg_scanner`] gem is used for collecting type information. It can be installed manually \nto the target SDK and requires MRI Ruby at least 2.3.\n\n#### Running type tracker\n\nThere are two possibilities to use the type tracker:\n_(I)_ using IJ/RubyMine plugin or _(II)_ requiring it from Ruby code.\n\n##### Using RubyMine plugin\n\nThe easiest way to run the plugin (and the most convenient for its development) is\nrunning it with special gradle task against IJ Ultimate snapshot:\n \n```\n./gradlew ide-plugin:runIde\n```\n\nThe task will compile the plugin, run IJ Ultimate with plugin \"installed\" in it.\nThere is no need in running anything manually in that case.\n\nIf you want to try it with existing RubyMine instance,\nyou should:\n\n1. Build it via `./gradlew ide-plugin:buildPlugin`\n2. Install plugin in the IDE\n    * Navigate to `File | Settings | Plugins | Install plugin from disk...`\n    * Locate plugin in `ide-plugin/build/distributions` and select.\n    * Restart IDE.\n\nNote that due to API changes the plugin may be incompatible with older RM instances.\n\n##### Using command line\n\n1. In order to collect the data for the script needs a contract server to be up and running;\n   it could be run by running\n   ```sh\n   ./gradlew contract-creator:runServer --args path-to-db.mv.db\n   ```\n   where `path-to-db.mv.db` is path where type contracts will be stored (H2 database file).\n\n1. Run the ruby script to be processed via [`arg-scanner`](arg_scanner/bin/arg-scanner)\n   binary.\n\n1. Use the data collected by the contract server.\n\n## Contributions\n\nAny kind of ideas, use cases, contributions and questions are very welcome\nas the project is just incubating.\nPlease feel free to create issues for any sensible request.\n\n[`arg_scanner`]: arg_scanner/README.md"
  },
  {
    "path": "arg_scanner/.gitignore",
    "content": "*.iml\n\n.bundle/\n.yardoc\nGemfile.lock\n_yardoc/\ncoverage/\ndoc/\npkg/\nspec/reports/\ntmp/\n*.bundle\n*.so\n*.o\n*.a\nmkmf.log\n"
  },
  {
    "path": "arg_scanner/Gemfile",
    "content": "source 'https://rubygems.org'\n\n# Specify your gem's dependencies in arg_scanner.gemspec\ngemspec\n\ngroup :test do\n  gem 'test-unit'\nend\n"
  },
  {
    "path": "arg_scanner/LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 JetBrains\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "arg_scanner/README.md",
    "content": "# ArgScanner [![Gem Version](https://badge.fury.io/rb/arg_scanner.svg)](https://badge.fury.io/rb/arg_scanner)\n\n`arg_scanner` is a gem with the purpose to track all method calls and\ndeliver the following information:\n\n* Method signature (arguments, their names and kinds) and declaration place\n* The types of argument variables given to each method call done\n\nThis information can be used then to calculate and use type contracts\nfor the analysed methods.\n\n`arg_scanner` is meant to be used as a binary to run any other ruby executable\nmanually so including it in the `Gemfile` is not necessary.\n\n## Installation\n\nThe recommended way to install it is to execute command:\n\n```\ngem install arg_scanner\n```\n**You will possibly need to install [native dependencies](#dependencies)**\n    \n## Building from sources\n\nIf you want to compile the gem from sources, just run the following commands:\n\n```    \nbundle install\nbundle exec rake install\n```\n    \nIf you have problems with native extension compilation, make sure you have\nactual version of [ruby-core-source gem](https://github.com/os97673/debase-ruby_core_source) and \nhave [native dependencies](#dependencies) installed. \n\n## Dependencies\n\n##### [Glib](https://developer.gnome.org/glib/)\n\nmacOS: `brew install glib`   \nDebian/Ubuntu: `sudo apt install libglib2.0-dev`  \nArch Linux: `sudo pacman -S glib2`  \n\n## Usage\n\n`arg_scanner` provides the `arg-scanner` binary which receives any number of\narguments and executes the given command in type tracking mode,\nfor example:\n\n```\narg-scanner --type-tracker --pipe-file-path=[pipe_file_path] bundle exec rake spec\n```\n`pipe_file_path` here is path to pipe file which is printed by server's stdout\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/JetBrains/ruby-type-inference\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n"
  },
  {
    "path": "arg_scanner/Rakefile",
    "content": "require \"bundler/gem_tasks\"\nrequire \"rake/extensiontask\"\nrequire 'rake/testtask'\n\nBASE_TEST_FILE_LIST = Dir['test/**/test_*.rb']\n\ntask :build => :compile\n\nRake::ExtensionTask.new(\"arg_scanner\") do |ext|\n  ext.lib_dir = \"lib/arg_scanner\"\nend\n\ndesc \"Test arg_scanner.\"\nRake::TestTask.new(:test => [:clean, :compile]) do |t|\n  t.libs += %w(./ext ./lib)\n  t.test_files = FileList[BASE_TEST_FILE_LIST]\n  t.verbose = true\nend\n\ntask :test => :lib\n\ntask :default => [:clobber, :compile, :test]\n"
  },
  {
    "path": "arg_scanner/arg_scanner.gemspec",
    "content": "# coding: utf-8\nlib = File.expand_path('../lib', __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'arg_scanner/version'\n\nGem::Specification.new do |spec|\n  spec.name = \"arg_scanner\"\n  spec.version = ArgScanner::VERSION\n  spec.authors = [\"Nickolay Viuginov\", \"Valentin Fondaratov\", \"Vladimir Koshelev\"]\n  spec.email = [\"viuginov.nickolay@gmail.com\", \"fondarat@gmail.com\", \"vkkoshelev@gmail.com\"]\n\n  spec.summary = %q{Program execution tracker to retrieve data types information}\n  spec.homepage = \"https://github.com/jetbrains/ruby-type-inference\"\n  spec.license = \"MIT\"\n\n  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'\n  # to allow pushing to a single host or delete this section to allow pushing to any host.\n  # if spec.respond_to?(:metadata)\n  #   spec.metadata['allowed_push_host'] = \"TODO: Set to 'http://mygemserver.com'\"\n  # else\n  #   raise \"RubyGems 2.0 or newer is required to protect against \" \\\n  #     \"public gem pushes.\"\n  # end\n\n  spec.files = `git ls-files -z`.split(\"\\x0\").reject do |f|\n    f.match(%r{^(test|spec|features)/})\n  end\n  spec.bindir = \"bin\"\n  spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f)}\n  spec.require_paths = [\"lib\"]\n  spec.extensions = [\"ext/arg_scanner/extconf.rb\"]\n\n  spec.add_development_dependency \"bundler\", \">= 1.13\"\n  spec.add_development_dependency \"rake\", \">= 12.0\"\n  spec.add_development_dependency \"rake-compiler\"\n  spec.add_dependency \"debase-ruby_core_source\", \">= 0.10.4\"\n  spec.add_dependency \"native-package-installer\", \">= 1.0.0\"\nend\n"
  },
  {
    "path": "arg_scanner/bin/arg-scanner",
    "content": "#!/usr/bin/env ruby\n\nrequire 'optparse'\nrequire 'arg_scanner/options'\nrequire 'arg_scanner/version'\n\noptions = ArgScanner::OPTIONS\noption_parser = OptionParser.new do |opts|\n  opts.banner = \"arg-scanner #{ArgScanner::VERSION}\" + <<~EOB\n  \n    Usage: arg-scanner [OPTIONS] <ruby cmdline> \n    arg-scanner is a ruby script mediator supposed to be run from the command line or IDE.\n        The data will be sent to a signature server so it must be running during arg-scanner execution.\n  EOB\n\n  opts.separator \"Options:\"\n  opts.on(\"--type-tracker\", \"enable type tracker\") do\n    options.enable_type_tracker = true\n  end\n  opts.on(\"--state-tracker\", \"enable state tracker\") do\n    options.enable_state_tracker = true\n  end\n\n  opts.on(\"--no-type-tracker\", \"disable type tracker\") do\n    options.enable_type_tracker = false\n  end\n  opts.on(\"--no-state-tracker\", \"disable state tracker\") do\n    options.enable_state_tracker = false\n  end\n\n  opts.on(\"--output-dir=[Dir]\", String, \"specify output directory (ignored by type tracker)\") do |dir|\n    options.output_dir = dir\n  end\n\n  opts.on(\"--catch-only-every-N-call=[N]\", Integer, \"randomly catches only 1/N of all calls to speed up performance (by default N = 1)\") do |n|\n    options.catch_only_every_n_call = n\n  end\n  opts.on(\"--project-root=[PATH]\", String, \"Specify project's root directory to catch every call from this directory. \"\\\n      \"Calls from other directories aren't guaranteed to be caught\") do |path|\n    options.project_root = path\n  end\n\n  opts.on(\"--pipe-file-path=[PATH]\", String, \"Specify pipe file path to connect to server\") do |path|\n    options.pipe_file_path = path\n  end\n\n  opts.on(\"--buffering\", \"enable buffering between arg-scanner and server. It speeds up arg-scanner but doesn't allow \"\\\n      \"to use arg-scanner \\\"interactively\\\". Disabled by default\") do |buffering|\n    options.buffering = buffering\n  end\nend\n\nbegin\n  option_parser.parse! ARGV\nrescue StandardError => e\n  puts option_parser\n  puts\n  puts e.message\n  exit 1\nend\n\nif ARGV.size < 1\n  puts option_parser\n  puts\n  puts \"Ruby program to trace must be specified.\"\n  exit 1\nend\n\noptions.set_env\n\nold_opts = ENV['RUBYOPT'] || ''\nstarter = \"-r #{File.expand_path(File.dirname(__FILE__))}/../lib/arg_scanner/starter\"\nunless old_opts.include? starter\n  ENV['RUBYOPT'] = starter\n  ENV['RUBYOPT'] += \" #{old_opts}\" if old_opts != ''\nend\n\n$0 = ARGV[0]\nKernel.exec *ARGV\n"
  },
  {
    "path": "arg_scanner/bin/console",
    "content": "#!/usr/bin/env ruby\n\nrequire \"bundler/setup\"\nrequire \"arg_scanner\"\n\n# You can add fixtures and/or initialization code here to make experimenting\n# with your gem easier. You can also use a different console, if you like.\n\n# (If you use this, don't forget to add pry to your Gemfile!)\n# require \"pry\"\n# Pry.start\n\nrequire \"irb\"\nIRB.start\n"
  },
  {
    "path": "arg_scanner/bin/rubymine-type-tracker",
    "content": "#!/usr/bin/env ruby\n# This is small script for launching type tracker under RubyMine's provided server. Acts like arg-scanner wrapper\nrequire 'optparse'\nrequire 'arg_scanner/version'\nrequire 'tmpdir'\nrequire 'json'\n\noption_parser = OptionParser.new do |opts|\n  opts.banner = <<~EOB\n    rubymine-type-tracker #{ArgScanner::VERSION}\n    \n    Usage: rubymine-type-tracker <ruby script to execute>\n        rubymine-type-tracker is a ruby script for easy launching some command under\n        RubyMine's type tracker. The data will be sent to a server run by RubyMine. \n        So before launching this script be sure project is opened in RubyMine with \n        \"Ruby Dynamic Code Insight\" plugin installed.\n  EOB\nend\n\nbegin\n  option_parser.parse! ARGV\n  if ARGV.size == 0\n    raise StandardError.new(\"\")\n  end\nrescue StandardError => e\n  puts option_parser\n  exit 1\nend\n\ndot_ruby_type_inference_dir = File.join(Dir.tmpdir, \".ruby-type-inference\")\nif File.directory?(dot_ruby_type_inference_dir)\n  match_jsons = Dir.foreach(dot_ruby_type_inference_dir).map do |file_name|\n    if file_name == '.' || file_name == '..'\n      next nil\n    end\n    json = JSON.parse(IO.read(File.join(dot_ruby_type_inference_dir, file_name)))\n    if json[\"projectPath\"] != Dir.pwd\n      next nil\n    end\n    next json\n  end.select { |x| x != nil }\nelse\n  match_jsons = []\nend\n\nif match_jsons.count == 1\n  json = match_jsons[0]\nelsif match_jsons.count > 1\n  STDERR.puts <<~EOB\n      Critical error! You may try to:\\n\n      1. Close RubyMine\n      2. Clean #{dot_ruby_type_inference_dir}\n      3. Open RubyMine\n  EOB\n  exit 1\nelsif match_jsons.count == 0\n  STDERR.puts <<~EOB\n      Error! You are possibly...\n      * launching this script under directory different from project \n        opened in RubyMine (please `cd` to dir firstly)\n      * haven't opened project in RubyMine \n      * haven't installed \"Ruby Dynamic Code Insight\" plugin in RubyMine\n  EOB\n  exit 1\nend\n\nto_exec = [\"arg-scanner\",\n           \"--type-tracker\",\n           \"--project-root=#{json[\"projectPath\"]}\",\n           \"--pipe-file-path=#{json[\"pipeFilePath\"]}\",\n           *ARGV]\n\nKernel.exec(*to_exec)\n"
  },
  {
    "path": "arg_scanner/bin/setup",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\nset -vx\n\nbundle install\n\n# Do any other automated setup that you need to do here\n"
  },
  {
    "path": "arg_scanner/ext/arg_scanner/arg_scanner.c",
    "content": "#include \"arg_scanner.h\"\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <stdarg.h>\n#include <netinet/in.h>\n#include <glib.h>\n\n//#define DEBUG_ARG_SCANNER 1\n\n#if RUBY_API_VERSION_CODE >= 20500\n  #if (RUBY_RELEASE_YEAR == 2017 && RUBY_RELEASE_MONTH == 10 && RUBY_RELEASE_DAY == 10) //workaround for 2.5.0-preview1\n    #define TH_CFP(thread) ((rb_control_frame_t *)(thread)->ec.cfp)\n  #else\n    #define TH_CFP(thread) ((rb_control_frame_t *)(thread)->ec->cfp)\n  #endif\n#else\n  #define TH_CFP(thread) ((rb_control_frame_t *)(thread)->cfp)\n#endif\n\n#ifdef DEBUG_ARG_SCANNER\n    #define LOG(f, args...) { fprintf(stderr, \"DEBUG: '%s'=\", #args); fprintf(stderr, f, ##args); fflush(stderr); }\n#else\n    #define LOG(...) {}\n#endif\n\n#define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))\ntypedef struct rb_trace_arg_struct rb_trace_arg_t;\n\nVALUE mArgScanner = Qnil;\nint types_ids[20];\n\nstatic VALUE c_signature;\n\n/**\n * Contains info related to explicitly passed args\n * For example:\n * def foo(a, b = 1); end\n *\n * `b` passed here implicitly:\n * foo(1)\n *\n * But here explicitly:\n * foo(1, 10)\n */\ntypedef struct\n{\n    ssize_t call_info_explicit_argc;   // Number of arguments that was explicitly passed by user\n    char **call_info_kw_explicit_args; // kw arguments names that was explicitly passed by user (null terminating array)\n} call_info_t;\n\ntypedef struct\n{\n    char *receiver_name;\n    char *method_name;\n    char *args_info;\n    char *path;\n    char *return_type_name;\n    ssize_t explicit_argc; // Number of arguments that was explicitly passed by user\n    int lineno;\n    int is_in_project_root; // Can be 0, 1 or -1 when project_root is not specified\n} signature_t;\n\nvoid Init_arg_scanner();\n\nstatic const char *ARG_SCANNER_EXIT_COMMAND = \"EXIT\";\nstatic const char *EMPTY_VALUE = \"\";\nstatic const int MAX_NUMBER_OF_MISSED_CALLS = 10;\n/**\n * There we keep information about signatures that have already been sent to server in order to not sent them again\n */\nstatic GTree *sent_to_server_tree;\n/**\n * Here we store map with key: signature_t and value: int number (how many times method was called with the same args)\n * If we got that any method is called with the same args more than MAX_NUMBER_OF_MISSED_CALLS times in a row then\n * we will ignore it.\n */\nstatic GTree *number_missed_calls_tree;\nstatic GSList *call_stack = NULL;\nstatic char *get_args_info(const char *const *explicit_kw_args);\nstatic VALUE handle_call(VALUE self, VALUE tp);\nstatic VALUE handle_return(VALUE self, VALUE tp);\nstatic VALUE destructor(VALUE self);\nstatic const char *calc_sane_class_name(VALUE ptr);\n\n// returns Qnil if ready; or string containing error message otherwise \nstatic VALUE check_if_arg_scanner_ready(VALUE self);\n\n// For testing\nstatic VALUE get_args_info_rb(VALUE self);\nstatic VALUE get_call_info_rb(VALUE self);\n\nstatic call_info_t get_call_info();\nstatic bool is_call_info_needed();\n\nstatic void call_info_t_free(call_info_t s)\n{\n    free(s.call_info_kw_explicit_args);\n}\n\nstatic void signature_t_free(signature_t *s)\n{\n    free(s->receiver_name);\n    free(s->method_name);\n    free(s->args_info);\n    free(s->path);\n    free(s->return_type_name);\n    free(s);\n}\n\n// Free signature_t partially leaving parts that are used in sent_to_server_tree_comparator\n// @see_also sent_to_server_tree_comparator\nstatic void signature_t_free_partially(signature_t *s)\n{\n    free(s->receiver_name);\n    s->receiver_name = NULL;\n\n    free(s->method_name);\n    s->method_name = NULL;\n}\n\n// Comparator for number_missed_calls_tree.\nstatic gint\nnumber_missed_calls_tree_comparator(gconstpointer x, gconstpointer y, gpointer user_data_ignored) {\n    const signature_t *a = x;\n    const signature_t *b = y;\n    int ret;\n\n    // Comparison using lineno and path theoretically should guarantees us unique.\n    // And compare lineno firstly because it's faster O(1) than comparing path which is O(path_len)\n    ret = a->lineno - b->lineno;\n    if (ret != 0) return ret;\n\n    ret = strcmp(a->path, b->path);\n    if (ret != 0) return ret;\n\n    return 0;\n}\n\n// Comparator for sent_to_server_tree.\n// If you want to change the way it compare then don't forget to\n// change signature_t_free_partially accordingly\n// @see_also signature_t_free_partially\nstatic gint\nsent_to_server_tree_comparator(gconstpointer x, gconstpointer y, gpointer user_data_ignored) {\n    const signature_t *a = x;\n    const signature_t *b = y;\n    int ret;\n\n    ret = number_missed_calls_tree_comparator(x, y, user_data_ignored);\n    if (ret != 0) return ret;\n\n    if (a->args_info != NULL && b->args_info != NULL) {\n        ret = strcmp(a->args_info, b->args_info);\n        if (ret != 0) return ret;\n    }\n\n    ret = strcmp(a->return_type_name, b->return_type_name);\n    if (ret != 0) return ret;\n\n    return 0;\n}\n\ninline int start_with(const char *str, const char *prefix) {\n    if (str == NULL || prefix == NULL) {\n        return -1;\n    }\n    while (*str != '\\0' && *prefix != '\\0') {\n        if (*str != *prefix) {\n            return 0;\n        }\n        str++;\n        prefix++;\n    }\n    return 1;\n}\n\nFILE *pipe_file = NULL;\nstatic char *project_root = NULL;\nstatic int catch_only_every_n_call = 1;\n\nstatic int file_exists(const char *file_path) {\n    return access(file_path, F_OK) != -1;\n}\n\nstatic VALUE init(VALUE self, VALUE pipe_file_path, VALUE buffering,\n                  VALUE project_root_local, VALUE catch_only_every_n_call_local) {\n    if (pipe_file_path != Qnil) {\n        pipe_file_path = rb_file_s_expand_path(1, &pipe_file_path); // https://ruby-doc.org/core-2.2.0/File.html#method-c-expand_path\n        const char *pipe_file_path_c = StringValueCStr(pipe_file_path);\n        if (!file_exists(pipe_file_path_c)) {\n            fprintf(stderr, \"Specified pipe file: %s doesn't exists\\n\", pipe_file_path_c);\n            exit(1);\n        }\n        pipe_file = fopen(pipe_file_path_c, \"w\");\n        if (pipe_file == NULL) {\n            fprintf(stderr, \"Cannot open pipe file \\\"%s\\\" with write access\\n\", pipe_file_path_c);\n            exit(1);\n        }\n\n        int buffering_disabled = buffering == Qnil;\n        if (buffering_disabled) {\n            setbuf(pipe_file, NULL);\n        }\n    }\n    if (project_root_local != Qnil) {\n        project_root = strdup(StringValueCStr(project_root_local));\n    }\n    if (catch_only_every_n_call_local != Qnil) {\n        if (sscanf(StringValueCStr(catch_only_every_n_call_local), \"%d\", &catch_only_every_n_call) != 1) {\n            fprintf(stderr, \"Please specify number in --catch-only-every-N-call arg\\n\");\n            exit(1);\n        }\n        srand(time(0));\n    }\n    return Qnil;\n}\n\nvoid Init_arg_scanner() {\n    mArgScanner = rb_define_module(\"ArgScanner\");\n    rb_define_module_function(mArgScanner, \"handle_call\", handle_call, 1);\n    rb_define_module_function(mArgScanner, \"handle_return\", handle_return, 1);\n    rb_define_module_function(mArgScanner, \"get_args_info\", get_args_info_rb, 0);\n    rb_define_module_function(mArgScanner, \"get_call_info\", get_call_info_rb, 0);\n    rb_define_module_function(mArgScanner, \"destructor\", destructor, 0);\n    rb_define_module_function(mArgScanner, \"check_if_arg_scanner_ready\", check_if_arg_scanner_ready, 0);\n    rb_define_module_function(mArgScanner, \"init\", init, 4);\n\n    sent_to_server_tree = g_tree_new_full(/*key_compare_func =*/sent_to_server_tree_comparator,\n                                          /*key_compare_data =*/NULL,\n                                          /*key_destroy_func =*/(GDestroyNotify)signature_t_free,\n                                          /*value_destroy_func =*/NULL);\n\n    // key_destroy_func is NULL because we will use the same keys for number_missed_calls_tree\n    // and sent_to_server_tree. And all memory management is done by sent_to_server_tree\n    number_missed_calls_tree = g_tree_new_full(/*key_compare_func =*/number_missed_calls_tree_comparator,\n                                               /*key_compare_data =*/NULL,\n                                               /*key_destroy_func =*/NULL,\n                                               /*value_destroy_func =*/NULL);\n}\n\ninline void push_to_call_stack(signature_t *signature) {\n    call_stack = g_slist_prepend(call_stack, (gpointer) signature);\n}\n\ninline signature_t *pop_from_call_stack() {\n    if (call_stack == NULL) {\n        return NULL;\n    }\n    signature_t *ret = (signature_t *) call_stack->data;\n\n    GSList *old_head = call_stack;\n    call_stack = g_slist_remove_link(call_stack, old_head);\n    g_slist_free_1(old_head);\n    return ret;\n}\n\ninline int is_call_stack_empty() {\n    return call_stack == NULL;\n}\n\n/**\n * Looks at the object at the top of this stack without removing it from the stack.\n */\ninline signature_t *top_of_call_stack() {\n    if (call_stack == NULL) {\n        return NULL;\n    }\n    return (signature_t *) call_stack[0].data;\n}\n\nrb_control_frame_t *\nmy_rb_vm_get_binding_creatable_next_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp)\n{\n    while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {\n        if (cfp->iseq) {\n            return (rb_control_frame_t *)cfp;\n        }\n\t    cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);\n    }\n    return 0;\n}\n\nstatic VALUE exit_from_handle_call_skipping_call() {\n    push_to_call_stack(NULL);\n    return Qnil;\n}\n\nstatic VALUE\nhandle_call(VALUE self, VALUE tp)\n{\n    signature_t sign_temp;\n    memset(&sign_temp, 0, sizeof(sign_temp));\n    sign_temp.lineno = FIX2INT(rb_funcall(tp, rb_intern(\"lineno\"), 0)); // Convert Ruby's Fixnum to C language int\n    VALUE path = rb_funcall(tp, rb_intern(\"path\"), 0);\n    path = rb_file_s_expand_path(1, &path); // https://ruby-doc.org/core-2.2.0/File.html#method-c-expand_path\n    sign_temp.path = StringValueCStr(path);\n\n    int is_in_project_root = start_with(sign_temp.path, project_root);\n\n    if (project_root != NULL && !is_in_project_root) {\n        signature_t *peek = top_of_call_stack();\n\n        if (!is_call_stack_empty() && (peek == NULL || !(peek->is_in_project_root))) {\n            return exit_from_handle_call_skipping_call();\n        }\n    }\n\n    if (project_root == NULL || !is_in_project_root) {\n        int number_of_missed_calls = (int)g_tree_lookup(number_missed_calls_tree, &sign_temp);\n        if (number_of_missed_calls > MAX_NUMBER_OF_MISSED_CALLS) {\n            return exit_from_handle_call_skipping_call();\n        }\n    }\n\n    if (catch_only_every_n_call != 1 && rand() % catch_only_every_n_call != 0) {\n        return exit_from_handle_call_skipping_call();\n    }\n\n    signature_t *sign = (signature_t *) calloc(1, sizeof(*sign));\n\n    sign->is_in_project_root = is_in_project_root;\n    sign->lineno = sign_temp.lineno;\n    sign->path = strdup(sign_temp.path);\n    sign->method_name = strdup(rb_id2name(SYM2ID(rb_funcall(tp, rb_intern(\"method_id\"), 0))));\n    sign->explicit_argc = -1;\n\n#ifdef DEBUG_ARG_SCANNER\n    LOG(\"Getting args info for %s %s %d \\n\", sign->method_name, sign->path, sign->lineno);\n#endif\n    call_info_t info;\n    info.call_info_kw_explicit_args = NULL;\n    if (is_call_info_needed()) {\n        info = get_call_info();\n        sign->explicit_argc = info.call_info_explicit_argc;\n    }\n\n    sign->args_info = get_args_info(info.call_info_kw_explicit_args);\n    call_info_t_free(info);\n\n    if (sign->args_info != NULL && strlen(sign->args_info) >= 1000) {\n        signature_t_free(sign);\n        return exit_from_handle_call_skipping_call();\n    }\n\n    push_to_call_stack(sign);\n    return Qnil;\n}\n\nstatic VALUE\nhandle_return(VALUE self, VALUE tp)\n{\n    signature_t *sign = pop_from_call_stack();\n    if (sign == NULL) {\n        return Qnil;\n    }\n    VALUE defined_class = rb_funcall(tp, rb_intern(\"defined_class\"), 0);\n\n    VALUE receiver_name = rb_mod_name(defined_class);\n\n    // if defined_class is nil then it means that method is invoked from anonymous module.\n    // Then trying to extract name of it's anonymous module. For more details see\n    // CallStatCompletionTest#testAnonymousModuleMethodCall\n    if (receiver_name == Qnil) {\n        VALUE this = rb_funcall(tp, rb_intern(\"self\"), 0);\n        receiver_name = rb_funcall(this, rb_intern(\"to_s\"), 0);\n    }\n\n    VALUE return_type_name = rb_funcall(tp, rb_intern(\"return_value\"), 0);\n\n    sign->receiver_name = strdup(StringValueCStr(receiver_name));\n    sign->return_type_name = strdup(calc_sane_class_name(return_type_name));\n\n    signature_t *sign_in_sent_to_server_tree = g_tree_lookup(sent_to_server_tree, sign);\n    if (sign_in_sent_to_server_tree == NULL) {\n        // Resets number of missed calls to 0\n        g_tree_insert(number_missed_calls_tree, /*key = */sign, /*value = */0);\n\n        // GTree will free memory allocated by sign by itself\n        g_tree_insert(sent_to_server_tree, /*key = */sign, /*value = */sign);\n\n        if (pipe_file != NULL) {\n            fprintf(pipe_file,\n                \"{\\\"method_name\\\":\\\"%s\\\",\\\"call_info_argc\\\":\\\"%d\\\",\\\"args_info\\\":\\\"%s\\\",\\\"visibility\\\":\\\"%s\\\",\"\n                \"\\\"path\\\":\\\"%s\\\",\\\"lineno\\\":\\\"%d\\\",\\\"receiver_name\\\":\\\"%s\\\",\\\"return_type_name\\\":\\\"%s\\\"}\\n\",\n                sign->method_name,\n                sign->explicit_argc,\n                sign->args_info != NULL ? sign->args_info : \"\",\n                \"PUBLIC\",\n                sign->path,\n                sign->lineno,\n                sign->receiver_name,\n                sign->return_type_name);\n        }\n\n        signature_t_free_partially(sign);\n    } else if (project_root == NULL || !sign->is_in_project_root) {\n        signature_t_free(sign);\n\n        int found = (int) g_tree_lookup(number_missed_calls_tree, sign_in_sent_to_server_tree);\n        g_tree_insert(number_missed_calls_tree, /*key = */sign_in_sent_to_server_tree, /*value = */found + 1);\n    }\n    return Qnil;\n}\n\nstatic call_info_t\nget_call_info() {\n    rb_thread_t *thread = ruby_current_thread;\n    rb_control_frame_t *cfp = TH_CFP(thread);\n\n    call_info_t empty;\n    empty.call_info_kw_explicit_args = NULL;\n    empty.call_info_explicit_argc = -1;\n\n    cfp += 3;\n    cfp = my_rb_vm_get_binding_creatable_next_cfp(thread, cfp);\n\n    if(cfp->iseq == NULL || cfp->pc == NULL || cfp->iseq->body == NULL) {\n        return empty;\n    }\n\n    const rb_iseq_t *iseq = (const rb_iseq_t *) cfp->iseq;\n\n    ptrdiff_t pc = cfp->pc - cfp->iseq->body->iseq_encoded;\n\n    const VALUE *iseq_original = rb_iseq_original_iseq(iseq);\n\n    int indent;\n    for (indent = 1; indent < 6; indent++) {\n        VALUE insn = iseq_original[pc - indent];\n        int tmp = (int)insn;\n        if(0 < tmp && tmp < 256) {\n            if(indent < 3) {\n                return empty;\n            }\n            call_info_t info;\n            struct rb_call_info *ci = (struct rb_call_info *)iseq_original[pc - indent + 1];\n            info.call_info_explicit_argc = ci->orig_argc;\n            info.call_info_kw_explicit_args = NULL;\n\n            if (ci->flag & VM_CALL_KWARG) {\n                struct rb_call_info_kw_arg *kw_args = ((struct rb_call_info_with_kwarg *)ci)->kw_arg;\n\n                size_t kwArgSize = kw_args->keyword_len;\n\n                VALUE kw_ary = rb_ary_new_from_values(kw_args->keyword_len, kw_args->keywords);\n\n                info.call_info_kw_explicit_args = (char **) malloc((kwArgSize + 1)*sizeof(*(info.call_info_kw_explicit_args)));\n\n                int i;\n                for (i = kwArgSize -1 ; i >= 0; --i) {\n                    VALUE kw = rb_ary_pop(kw_ary);\n                    const char *kw_name = rb_id2name(SYM2ID(kw));\n\n                    info.call_info_kw_explicit_args[i] = kw_name;\n                }\n                info.call_info_kw_explicit_args[kwArgSize] = NULL;\n            } else {\n                info.call_info_kw_explicit_args = malloc(sizeof(*info.call_info_kw_explicit_args));\n                info.call_info_kw_explicit_args[0] = NULL;\n            }\n            return info;\n        }\n    }\n    return empty;\n}\n\nstatic const char*\ncalc_sane_class_name(VALUE ptr)\n{\n    VALUE klass = rb_obj_class(ptr);\n\n    const char* klass_name;\n    // may be false, see `object.c#rb_class_get_superclass`\n    if (klass == Qfalse) {\n        klass_name = \"<err>\";\n    }\n    else\n    {\n        klass_name = rb_class2name(klass);\n    }\n\n    // returned value may be NULL, see `variable.c#rb_class2name`\n    if (klass_name == NULL)\n    {\n        klass_name = \"<err>\";\n    }\n\n    return klass_name;\n}\n\nstatic char *\nfast_join_array(char sep, size_t count, const char **strings)\n{\n    size_t lengths[count + 1];\n    size_t i;\n    char *result;\n\n    lengths[0] = 0;\n\n    for (i = 0; i < count; i++)\n    {\n        const char *str = strings[i];\n        size_t length;\n        if (!str)\n            length = 0;\n        else\n            length = strlen(str) + (i > 0); // 1 for separator before\n\n        lengths[i + 1] = lengths[i] + length;\n    }\n\n    result = (char *)malloc(sizeof(*result) * (1 + lengths[count]));\n\n    for (i = 0; i < count; i++)\n    {\n        const char *str = strings[i];\n        if (str)\n        {\n            int start = lengths[i];\n            if (i > 0)\n                result[start++] = sep;\n\n            memcpy(result + start, str, sizeof(*result) * (lengths[i + 1] - start));\n        }\n    }\n\n    result[lengths[count]] = 0;\n\n    return result;\n}\n\nstatic char *\nfast_join(char sep, size_t count, ...)\n{\n    char *strings[count];\n    size_t i;\n    va_list ap;\n\n    va_start(ap, count);\n    for (i = 0; i < count; i++)\n    {\n        strings[i] = va_arg(ap, char *);\n    }\n    va_end(ap);\n\n    return fast_join_array(sep, count, strings);\n}\n\n/**\n * Checks that `container` contains `element`\n */\nstatic int contains(const char *const *container, const char *element) {\n    if (container == NULL || element == NULL) {\n        return 0;\n    }\n    const char *const *iterator = container;\n    while (*iterator != NULL) {\n        if (strcmp(*iterator, element) == 0) {\n            return 1;\n        }\n        ++iterator;\n    }\n    return 0;\n}\n\n#define JOIN_KW_NAMES_AND_TYPES_BUF_SIZE 2048\nstatic char join_kw_names_and_types_buf[JOIN_KW_NAMES_AND_TYPES_BUF_SIZE];\n/**\n * Null terminating array which contains strings of explicitly passed kw args.\n * It's used for join_kw_names_and_types\n */\nstatic const char *const *join_kw_names_and_types_explicit_kw_args = NULL;\n\n/**\n * This function is used for concatenating hash keys and value's types.\n * Be sure that buf is at least JOIN_KW_NAMES_AND_TYPES_BUF_SIZE bytes.\n * If join_kw_names_and_types_buf size = JOIN_KW_NAMES_AND_TYPES_BUF_SIZE\n * isn't enough then this buf will contain invalid information\n */\nstatic int join_kw_names_and_types(VALUE key, VALUE val, VALUE ignored) {\n    const char *kw_name = rb_id2name(SYM2ID(key));\n    const char *kw_type = calc_sane_class_name(val);\n\n    const char *const *explicit_kw_args_iterator = join_kw_names_and_types_explicit_kw_args;\n\n    // Just such behaviour: when join_kw_names_and_types_explicit_kw_args is\n    // not provided then consider every kw arg as explicitly passed by user\n    int is_explicit = explicit_kw_args_iterator == NULL;\n\n    if (explicit_kw_args_iterator != NULL) {\n        while(*explicit_kw_args_iterator != NULL) {\n            if (strcmp(*explicit_kw_args_iterator, kw_name) == 0) {\n                is_explicit = 1;\n                break;\n            }\n            ++explicit_kw_args_iterator;\n        }\n    }\n\n    if (is_explicit) {\n        // Check that buf is not empty\n        if (join_kw_names_and_types_buf[0] != '\\0') {\n            strncat(join_kw_names_and_types_buf, \";\", JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1);\n        }\n        strncat(join_kw_names_and_types_buf, \"KEYREST,\", JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1);\n        strncat(join_kw_names_and_types_buf, kw_type, JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1);\n        strncat(join_kw_names_and_types_buf, \",\", JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1);\n        strncat(join_kw_names_and_types_buf, kw_name, JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1);\n    }\n    return ST_CONTINUE;\n}\n\nstatic char*\nget_args_info(const char *const *explicit_kw_args)\n{\n    rb_thread_t *thread;\n    rb_control_frame_t *cfp;\n\n    thread = ruby_current_thread;\n    cfp = TH_CFP(thread);\n\n    cfp += 2;\n\n    VALUE *ep = cfp->ep;\n    ep -= cfp->iseq->body->local_table_size;\n\n    size_t param_size = cfp->iseq->body->param.size;\n    size_t lead_num = cfp->iseq->body->param.lead_num;\n    size_t opt_num = cfp->iseq->body->param.opt_num;\n    size_t post_num = cfp->iseq->body->param.post_num;\n\n    unsigned int has_rest = cfp->iseq->body->param.flags.has_rest;\n    unsigned int has_kw = cfp->iseq->body->param.flags.has_kw;\n    unsigned int has_kwrest = cfp->iseq->body->param.flags.has_kwrest;\n    unsigned int has_block = cfp->iseq->body->param.flags.has_block;\n\n    LOG(\"%d\\n\", param_size);\n    LOG(\"%d\\n\", lead_num);\n    LOG(\"%d\\n\", opt_num);\n    LOG(\"%d\\n\", post_num);\n\n    LOG(\"%d\\n\", has_rest);\n    LOG(\"%d\\n\", has_kw);\n    LOG(\"%d\\n\", has_kwrest);\n    LOG(\"%d\\n\", has_block);\n\n    if (param_size == 0) {\n        return 0;\n    }\n\n    const char **types = (const char **)malloc(param_size * sizeof(*types));\n    size_t i, ans_iterator;\n    int types_iterator;\n\n    ans_iterator = 0;\n\n    int new_version_flag = strcmp(RUBY_VERSION, \"2.4.0\") >= 0 ? 1 : 0;\n    LOG(\"%d\\n\", new_version_flag);\n\n    for(i = param_size - 1 - new_version_flag, types_iterator = 0; (size_t)types_iterator < param_size; i--, types_iterator++)\n    {\n        types[types_iterator] = calc_sane_class_name(ep[i - 1]);\n        types_ids[types_iterator] = i - 1;\n        LOG(\"Type #%d=%s\\n\", types_iterator, types[types_iterator])\n    }\n\n    types_iterator--;\n\n    if(has_kw) {\n        param_size--;\n    }\n\n    char **ans = (char **)malloc(param_size * sizeof(*ans));\n\n    for(i = 0; i < lead_num; i++, ans_iterator++, types_iterator--)\n    {\n        const char* name = rb_id2name(cfp->iseq->body->local_table[ans_iterator]);\n        ans[ans_iterator] = fast_join(',', 3, \"REQ\", types[types_iterator], name);\n    }\n\n    for(i = 0; i < opt_num; i++, ans_iterator++, types_iterator--)\n    {\n        const char* name = rb_id2name(cfp->iseq->body->local_table[ans_iterator]);\n        ans[ans_iterator] = fast_join(',', 3, \"OPT\", types[types_iterator], name);\n    }\n\n    for(i = 0; i < has_rest; i++, ans_iterator++, types_iterator--)\n    {\n        const char* name = rb_id2name(cfp->iseq->body->local_table[ans_iterator]);\n        ans[ans_iterator] = fast_join(',', 3, \"REST\", types[types_iterator], name);\n    }\n\n    for(i = 0; i < post_num; i++, ans_iterator++, types_iterator--)\n    {\n        const char* name = rb_id2name(cfp->iseq->body->local_table[ans_iterator]);\n        ans[ans_iterator] = fast_join(',', 3, \"POST\", types[types_iterator], name);\n    }\n\n\n    if(cfp->iseq->body->param.keyword != NULL)\n    {\n        const ID *keywords = cfp->iseq->body->param.keyword->table;\n        size_t kw_num = cfp->iseq->body->param.keyword->num;\n        size_t required_num = cfp->iseq->body->param.keyword->required_num;\n        size_t rest_start = cfp->iseq->body->param.keyword->rest_start;\n\n        LOG(\"%d %d\\n\", kw_num, required_num)\n\n        for(i = 0; i < required_num; i++, ans_iterator++, types_iterator--)\n        {\n            ID key = keywords[i];\n            ans[ans_iterator] = fast_join(',', 3, \"KEYREQ\", types[types_iterator], rb_id2name(key));\n        }\n        for(i = required_num; i < kw_num; i++, types_iterator--)\n        {\n            ID key = keywords[i];\n            const char *name = rb_id2name(key);\n            if (explicit_kw_args == NULL || contains(explicit_kw_args, name)) {\n                ans[ans_iterator++] = fast_join(',', 3, \"KEY\", types[types_iterator], name);\n            }\n        }\n\n        if (param_size - has_block > 1 && has_kwrest && TYPE(ep[types_ids[types_iterator]]) == T_FIXNUM) {\n            types_iterator--;\n        }\n\n        if (has_kwrest)\n        {\n            char *buf = malloc(JOIN_KW_NAMES_AND_TYPES_BUF_SIZE * sizeof(*buf));\n            buf[0] = '\\0';\n            join_kw_names_and_types_buf[0] = '\\0';\n            join_kw_names_and_types_explicit_kw_args = explicit_kw_args;\n\n            // This function call will concatenate info into join_kw_names_and_types_buf\n            rb_hash_foreach(ep[types_ids[types_iterator]], join_kw_names_and_types, Qnil);\n\n            // Checking that join_kw_names_and_types_buf isn't possibly containing invalid info.\n            // See join_kw_names_and_types documentation to understand why it can be invalid\n            size_t len = strlen(join_kw_names_and_types_buf);\n            if (len > 0 && len < JOIN_KW_NAMES_AND_TYPES_BUF_SIZE - 1) {\n                strncpy(buf, join_kw_names_and_types_buf, JOIN_KW_NAMES_AND_TYPES_BUF_SIZE);\n                ans[ans_iterator++] = buf;\n            }\n            join_kw_names_and_types_explicit_kw_args = NULL;\n            types_iterator--;\n        }\n    }\n\n    for(i = 0; i < has_block; i++, ans_iterator++, types_iterator--)\n    {\n        const char* name = rb_id2name(cfp->iseq->body->local_table[ans_iterator]);\n        ans[ans_iterator] = fast_join(',', 3, \"BLOCK\", types[types_iterator], name);\n    }\n\n    LOG(\"%d\\n\", ans_iterator)\n    char *answer = fast_join_array(';', ans_iterator, ans);\n\n    for(i = 0; i < ans_iterator; i++) {\n        LOG(\"free2 %d %d =%s= \\n\", ans[i], strlen(ans[i]), ans[i]);\n        free(ans[i]);\n    }\n\n    LOG(\"%d %d %d\", ans_iterator, param_size, types_iterator);\n    assert(types_iterator <= 0);\n\n    free(types);\n    free(ans);\n\n    return answer;\n}\n\nstatic VALUE\nget_args_info_rb(VALUE self)\n{\n    call_info_t info;\n    info.call_info_kw_explicit_args = NULL;\n    if (is_call_info_needed()) {\n        info = get_call_info();\n    }\n\n    char *args_info = get_args_info(info.call_info_kw_explicit_args);\n    call_info_t_free(info);\n    VALUE ret = args_info ? rb_str_new_cstr(args_info) : Qnil;\n    free(args_info);\n    return ret;\n}\n\nstatic VALUE\nget_call_info_rb(VALUE self)\n{\n    if (is_call_info_needed())\n    {\n        call_info_t info = get_call_info();\n\n        VALUE ans;\n        ans = rb_ary_new();\n        rb_ary_push(ans, LONG2FIX(info.call_info_explicit_argc));\n        if (info.call_info_kw_explicit_args != NULL) {\n            const char *const *kwarg = info.call_info_kw_explicit_args;\n            int explicit_kw_count = 0;\n            while (*kwarg != NULL) {\n                ++explicit_kw_count;\n                ++kwarg;\n            }\n            char *answer = fast_join_array(',', explicit_kw_count, info.call_info_kw_explicit_args);\n            rb_ary_push(ans, rb_str_new_cstr(answer));\n            free(answer);\n        }\n\n        call_info_t_free(info);\n\n        return ans;\n    }\n    else\n    {\n        return Qnil;\n    }\n}\n\nstatic bool\nis_call_info_needed()\n{\n    rb_thread_t *thread;\n    rb_control_frame_t *cfp;\n\n    thread = ruby_current_thread;\n    cfp = TH_CFP(thread);\n    cfp += 2;\n\n    return (cfp->iseq->body->param.flags.has_opt\n        || cfp->iseq->body->param.flags.has_kwrest\n        || cfp->iseq->body->param.flags.has_rest\n        || (cfp->iseq->body->param.keyword != NULL && cfp->iseq->body->param.keyword->required_num == 0));\n}\n\nstatic VALUE \ncheck_if_arg_scanner_ready(VALUE self) {\n    char error_msg[1024];\n    if (pipe_file == NULL) {\n        snprintf(error_msg, sizeof(error_msg)/sizeof(*error_msg), \"Pipe file is not specified\");\n        return rb_str_new_cstr(error_msg);\n    }\n    return Qnil;\n}\n\nstatic VALUE\ndestructor(VALUE self) {\n    g_tree_destroy(sent_to_server_tree);\n    g_tree_destroy(number_missed_calls_tree);\n    fprintf(pipe_file, \"%s\\n\", ARG_SCANNER_EXIT_COMMAND);\n    fclose(pipe_file);\n    free(project_root);\n    return Qnil;\n}\n"
  },
  {
    "path": "arg_scanner/ext/arg_scanner/arg_scanner.h",
    "content": "#ifndef ARG_SCANNER_H\n#define ARG_SCANNER_H 1\n\n#include \"ruby.h\"\n#include \"vm_core.h\"\n#include \"version.h\"\n#include \"iseq.h\"\n#include \"method.h\"\n\n#endif /* ARG_SCANNER_H */\n"
  },
  {
    "path": "arg_scanner/ext/arg_scanner/extconf.rb",
    "content": "require \"mkmf\"\n\nRbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']\n\nrequire \"debase/ruby_core_source\"\nrequire \"native-package-installer\"\n\nclass NilClass\n  def empty?; true; end\nend\n\n# Just a replacement of have_header because have_header searches not recursively :(\ndef real_have_header(header_name)\n  if (have_header(header_name))\n    return true\n  end\n  yes_msg = \"checking for #{header_name}... yes\"\n  no_msg = \"checking for #{header_name}... no\"\n\n  include_env = ENV[\"C_INCLUDE_PATH\"]\n  if !include_env.empty? && !Dir.glob(\"#{include_env}/**/#{header_name}\").empty?\n    puts yes_msg\n    return true\n  end\n  if !Dir.glob(\"/usr/include/**/#{header_name}\").empty?\n    puts yes_msg\n    return true\n  end\n  puts no_msg\n  return false\nend\n\nif !real_have_header('glib.h') &&\n    !NativePackageInstaller.install(:alt_linux => \"glib2-devel\",\n                                    :debian => \"libglib2.0-dev\",\n                                    :redhat => \"glib2-devel\",\n                                    :arch_linux => \"glib2\",\n                                    :homebrew => \"glib\",\n                                    :macports => \"glib2\",\n                                    :msys2 => \"glib2\")\n  exit(false)\nend\n\nhdrs = proc {\n  have_header(\"vm_core.h\") and\n  have_header(\"iseq.h\") and\n  have_header(\"version.h\") and\n      have_header(\"vm_core.h\") and\n      have_header(\"vm_insnhelper.h\") and\n      have_header(\"vm_core.h\") and\n      have_header(\"method.h\")\n}\n\n# Allow use customization of compile options. For example, the\n# following lines could be put in config_options to to turn off\n# optimization:\n#   $CFLAGS='-fPIC -fno-strict-aliasing -g3 -ggdb -O2 -fPIC'\nconfig_file = File.join(File.dirname(__FILE__), 'config_options.rb')\nload config_file if File.exist?(config_file)\n\nif ENV['debase_debug']\n  $CFLAGS+=' -Wall -Werror -g3'\nend\n\n$CFLAGS += ' `pkg-config --cflags --libs glib-2.0`'\n$DLDFLAGS += ' `pkg-config --cflags --libs glib-2.0`'\n\ndir_config(\"ruby\")\nif !Debase::RubyCoreSource.create_makefile_with_core(hdrs, \"arg_scanner/arg_scanner\")\n  STDERR.print(\"Makefile creation failed\\n\")\n  STDERR.print(\"*************************************************************\\n\\n\")\n  STDERR.print(\"  NOTE: If your headers were not found, try passing\\n\")\n  STDERR.print(\"        --with-ruby-include=PATH_TO_HEADERS      \\n\\n\")\n  STDERR.print(\"*************************************************************\\n\\n\")\n  exit(1)\nend"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/options.rb",
    "content": "require 'ostruct'\n\nmodule ArgScanner\n  OPTIONS = OpenStruct.new(\n      :enable_type_tracker => ENV['ARG_SCANNER_ENABLE_TYPE_TRACKER'],\n      :enable_state_tracker => ENV['ARG_SCANNER_ENABLE_STATE_TRACKER'],\n      :output_directory => ENV['ARG_SCANNER_DIR'],\n      :catch_only_every_n_call => ENV['ARG_SCANNER_CATCH_ONLY_EVERY_N_CALL'] || 1,\n      :project_root => ENV['ARG_SCANNER_PROJECT_ROOT'],\n      :pipe_file_path => ENV['ARG_SCANNER_PIPE_FILE_PATH'] || '',\n      :buffering => ENV['ARG_SCANNER_BUFFERING']\n  )\n\n  def OPTIONS.set_env\n    ENV['ARG_SCANNER_ENABLE_TYPE_TRACKER'] = self.enable_type_tracker ? \"1\" : nil\n    ENV['ARG_SCANNER_ENABLE_STATE_TRACKER'] = self.enable_state_tracker ? \"1\" : nil\n    ENV['ARG_SCANNER_DIR'] = self.output_directory\n    ENV['ARG_SCANNER_CATCH_ONLY_EVERY_N_CALL'] = self.catch_only_every_n_call.to_s\n    ENV['ARG_SCANNER_PROJECT_ROOT'] = self.project_root\n    ENV['ARG_SCANNER_PIPE_FILE_PATH'] = self.pipe_file_path\n    ENV['ARG_SCANNER_BUFFERING'] = self.buffering ? \"1\" : nil\n  end\nend\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/require_all.rb",
    "content": "# Copyright (c) 2009 Jarmo Pertman\n\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nmodule RequireAll\n  # A wonderfully simple way to load your code.\n  #\n  # The easiest way to use require_all is to just point it at a directory\n  # containing a bunch of .rb files.  These files can be nested under\n  # subdirectories as well:\n  #\n  #  require_all 'lib'\n  #\n  # This will find all the .rb files under the lib directory and load them.\n  # The proper order to load them in will be determined automatically.\n  #\n  # If the dependencies between the matched files are unresolvable, it will\n  # throw the first unresolvable NameError.\n  #\n  # You can also give it a glob, which will enumerate all the matching files:\n  #\n  #  require_all 'lib/**/*.rb'\n  #\n  # It will also accept an array of files:\n  #\n  #  require_all Dir.glob(\"blah/**/*.rb\").reject { |f| stupid_file(f) }\n  #\n  # Or if you want, just list the files directly as arguments:\n  #\n  #  require_all 'lib/a.rb', 'lib/b.rb', 'lib/c.rb', 'lib/d.rb'\n  #\n  def require_all(*args)\n    # Handle passing an array as an argument\n    args.flatten!\n\n    options = {:method => :require}\n    options.merge!(args.pop) if args.last.is_a?(Hash)\n\n    if args.empty?\n      puts \"no files were loaded due to an empty Array\" if $DEBUG\n      return false\n    end\n\n    if args.size > 1\n      # Expand files below directories\n      files = args.map do |path|\n        if File.directory? path\n          Dir[File.join(path, '**', '*.rb')]\n        else\n          path\n        end\n      end.flatten\n    else\n      arg = args.first\n      begin\n        # Try assuming we're doing plain ol' require compat\n        stat = File.stat(arg)\n\n        if stat.file?\n          files = [arg]\n        elsif stat.directory?\n          files = Dir.glob File.join(arg, '**', '*.rb')\n        else\n          raise ArgumentError, \"#{arg} isn't a file or directory\"\n        end\n      rescue SystemCallError\n        # If the stat failed, maybe we have a glob!\n        files = Dir.glob arg\n\n        # Maybe it's an .rb file and the .rb was omitted\n        if File.file?(arg + '.rb')\n          file = arg + '.rb'\n          options[:method] != :autoload ? Kernel.send(options[:method], file) : __autoload(file, file, options)\n          return true\n        end\n\n        # If we ain't got no files, the glob failed\n        raise LoadError, \"no such file to load -- #{arg}\" if files.empty?\n      end\n    end\n\n    return if files.empty?\n\n    if options[:method] == :autoload\n      files.map! { |file_| [file_, File.expand_path(file_)] }\n      files.each do |file_, full_path|\n        __autoload(file_, full_path, options)\n      end\n\n      return true\n    end\n\n    files.map! { |file_| File.expand_path file_ }\n    files.sort!\n\n    begin\n      failed = []\n      first_name_error = nil\n\n      # Attempt to load each file, rescuing which ones raise NameError for\n      # undefined constants.  Keep trying to successively reload files that\n      # previously caused NameErrors until they've all been loaded or no new\n      # files can be loaded, indicating unresolvable dependencies.\n      files.each do |file_|\n        begin\n          Kernel.send(options[:method], file_)\n        rescue NameError => ex\n          failed << file_\n          first_name_error ||= ex\n        rescue ArgumentError => ex\n          # Work around ActiveSuport freaking out... *sigh*\n          #\n          # ActiveSupport sometimes throws these exceptions and I really\n          # have no idea why.  Code loading will work successfully if these\n          # exceptions are swallowed, although I've run into strange\n          # nondeterministic behaviors with constants mysteriously vanishing.\n          # I've gone spelunking through dependencies.rb looking for what\n          # exactly is going on, but all I ended up doing was making my eyes\n          # bleed.\n          #\n          # FIXME: If you can understand ActiveSupport's dependencies.rb\n          # better than I do I would *love* to find a better solution\n          raise unless ex.message[\"is not missing constant\"]\n\n          STDERR.puts \"Warning: require_all swallowed ActiveSupport 'is not missing constant' error\"\n          STDERR.puts ex.backtrace[0..9]\n        end\n      end\n\n      # If this pass didn't resolve any NameErrors, we've hit an unresolvable\n      # dependency, so raise one of the exceptions we encountered.\n      if failed.size == files.size\n        raise first_name_error\n      else\n        files = failed\n      end\n    end until failed.empty?\n\n    true\n  end\n\n  # Works like require_all, but paths are relative to the caller rather than\n  # the current working directory\n  def require_rel(*paths)\n    # Handle passing an array as an argument\n    paths.flatten!\n    return false if paths.empty?\n\n    source_directory = File.dirname caller.first.sub(/:\\d+$/, '')\n    paths.each do |path|\n      require_all File.join(source_directory, path)\n    end\n  end\n\n  # Loads all files like require_all instead of requiring\n  def load_all(*paths)\n    require_all paths, :method => :load\n  end\n\n  # Loads all files by using relative paths of the caller rather than\n  # the current working directory\n  def load_rel(*paths)\n    paths.flatten!\n    return false if paths.empty?\n\n    source_directory = File.dirname caller.first.sub(/:\\d+$/, '')\n    paths.each do |path|\n      require_all File.join(source_directory, path), :method => :load\n    end\n  end\n\n  # Performs Kernel#autoload on all of the files rather than requiring immediately.\n  #\n  # Note that all Ruby files inside of the specified directories should have same module name as\n  # the directory itself and file names should reflect the class/module names.\n  # For example if there is a my_file.rb in directories dir1/dir2/ then\n  # there should be a declaration like this in my_file.rb:\n  #   module Dir1\n  #     module Dir2\n  #       class MyFile\n  #         ...\n  #       end\n  #     end\n  #  end\n  #\n  # If the filename and namespaces won't match then my_file.rb will be loaded into wrong module!\n  # Better to fix these files.\n  #\n  # Set $DEBUG=true to see how files will be autoloaded if experiencing any problems.\n  #\n  # If trying to perform autoload on some individual file or some inner module, then you'd have\n  # to always specify *:base_dir* option to specify where top-level namespace resides.\n  # Otherwise it's impossible to know the namespace of the loaded files.\n  #\n  # For example loading only my_file.rb from dir1/dir2 with autoload_all:\n  #\n  #   autoload_all File.dirname(__FILE__) + '/dir1/dir2/my_file',\n  #                :base_dir => File.dirname(__FILE__) + '/dir1'\n  #\n  # WARNING: All modules will be created even if files themselves aren't loaded yet, meaning\n  # that all the code which depends of the modules being loaded or not will not work, like usages\n  # of define? and it's friends.\n  #\n  # Also, normal caveats of using Kernel#autoload apply - you have to remember that before\n  # applying any monkey-patches to code using autoload, you'll have to reference the full constant\n  # to load the code before applying your patch!\n\n  def autoload_all(*paths)\n    paths.flatten!\n    return false if paths.empty?\n    require \"pathname\"\n\n    options = {:method => :autoload}\n    options.merge!(paths.pop) if paths.last.is_a?(Hash)\n\n    paths.each do |path|\n      require_all path, {:base_dir => path}.merge(options)\n    end\n  end\n\n  # Performs autoloading relatively from the caller instead of using current working directory\n  def autoload_rel(*paths)\n    paths.flatten!\n    return false if paths.empty?\n    require \"pathname\"\n\n    options = {:method => :autoload}\n    options.merge!(paths.pop) if paths.last.is_a?(Hash)\n\n    source_directory = File.dirname caller.first.sub(/:\\d+$/, '')\n    paths.each do |path|\n      file_path = Pathname.new(source_directory).join(path).to_s\n      require_all file_path, {:method => :autoload,\n                              :base_dir => source_directory}.merge(options)\n    end\n  end\n\n  private\n\n  def __autoload(file, full_path, options)\n    last_module = \"Object\" # default constant where namespaces are created into\n    begin\n      base_dir = Pathname.new(options[:base_dir]).realpath\n    rescue Errno::ENOENT\n      raise LoadError, \":base_dir doesn't exist at #{options[:base_dir]}\"\n    end\n    Pathname.new(file).realpath.descend do |entry|\n      # skip until *entry* is same as desired directory\n      # or anything inside of it avoiding to create modules\n      # from the top-level directories\n      next if (entry <=> base_dir) < 0\n\n      # get the module into which a new module is created or\n      # autoload performed\n      mod = Object.class_eval(last_module)\n\n      without_ext = entry.basename(entry.extname).to_s\n      const = without_ext.split(\"_\").map {|word| word.capitalize}.join\n\n      if entry.directory?\n        mod.class_eval \"module #{const} end\"\n        last_module += \"::#{const}\"\n      else\n        mod.class_eval do\n          puts \"autoloading #{mod}::#{const} from #{full_path}\" if $DEBUG\n          autoload const, full_path\n        end\n      end\n    end\n  end\n\nend"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/starter.rb",
    "content": "# starter.rb is loaded with \"ruby -r\" option from bin/arg-scanner\n# or by IDEA also with \"ruby -r\" option\n\nunless ENV[\"ARG_SCANNER_ENABLE_STATE_TRACKER\"].nil?\n  require_relative 'state_tracker'\n  ArgScanner::StateTracker.new\nend\n\nunless ENV[\"ARG_SCANNER_ENABLE_TYPE_TRACKER\"].nil?\n  require_relative 'arg_scanner'\n  require_relative 'type_tracker'\n\n  # instantiating type tracker will enable calls tracing and sending the data\n  ArgScanner::TypeTracker.instance\nend\n\n\n\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/state_tracker.rb",
    "content": "require \"set\"\nrequire_relative \"require_all\"\nrequire_relative \"workspace\"\n\n\nmodule ArgScanner\n  class StateTracker\n    def initialize\n      @workspace = Workspace.new\n      @workspace.on_process_start\n      at_exit do\n        begin\n          require_extra_libs\n          @workspace.open_output_json(\"classes\") { |file| print_json(file) }\n        ensure\n          @workspace.on_process_exit\n        end\n      end\n    end\n\n    private\n    def require_extra_libs\n      begin\n        RequireAll.require_all Rails.root.join('lib')\n      rescue Exception => e\n      end\n      begin\n        Rails.application.eager_load!\n      rescue Exception => e\n      end\n    end\n\n    def print_json(file)\n      result = {\n        :top_level_constants => parse_top_level_constants,\n        :modules => modules_to_json,\n        :load_path => $:\n      }\n      require \"json\"\n      file.puts(JSON.dump(result))\n    end\n\n    def parse_top_level_constants\n      Module.constants.select { |const| Module.const_defined?(const)}.map do |const|\n        begin\n          value = Module.const_get(const)\n          (!value.is_a? Module) ? {\n              :name => const,\n              :class_name => value.class,\n              :extended => get_extra_methods(value)} : nil\n        rescue Exception => e\n        end\n      end.compact\n    end\n\n    def get_extra_methods(value)\n      value.methods - value.public_methods\n    end\n\n    def method_to_json(method)\n      ret = {\n          :name => method.name,\n          :parameters => method.parameters\n      }\n      unless method.source_location.nil?\n        ret[:path] = method.source_location[0]\n        ret[:line] = method.source_location[1]\n      end\n      ret\n    rescue Exception => e\n      nil\n    end\n\n    def module_to_json(mod)\n      ret = {\n        :name => mod.to_s,\n        :type => mod.class.to_s,\n        :singleton_class_ancestors => mod.singleton_class.ancestors.map{|it| it.to_s},\n        :ancestors => mod.ancestors.map{|it| it.to_s}, # map to_s is needed because for example \"Psych\" parsed not correctly into JSON format\n                                                       # it's parsed as: \"{}\\n\" check it by launching in rails console: \"JSON.generate(Psych)\"\n        :class_methods => mod.methods(false).map {|method| method_to_json(mod.method(method))}.compact,\n        :instance_methods => mod.instance_methods(false).map {|method| method_to_json(mod.instance_method(method))}.compact\n      }\n      ret[:superclass] = mod.superclass if mod.is_a? Class\n      ret\n    rescue Exception => e\n      nil\n    end\n\n    def modules_to_json\n      ObjectSpace.each_object(Module).map {|mod| module_to_json(mod)}\n    end\n  end\nend\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/type_tracker.rb",
    "content": "require 'set'\nrequire 'socket'\nrequire 'singleton'\nrequire 'thread'\n\nrequire_relative 'options'\n\nmodule ArgScanner\n\n  class TypeTrackerPerformanceMonitor\n    def initialize\n      @enable_debug = ENV[\"ARG_SCANNER_DEBUG\"]\n      @call_counter = 0\n      @handled_call_counter = 0\n      @submitted_call_counter = 0\n      @old_handled_call_counter = 0\n      @time = Time.now\n    end\n\n\n    def on_call\n      @submitted_call_counter += 1\n    end\n\n    def on_return\n      @call_counter += 1\n\n      if enable_debug && call_counter % 100000 == 0\n        $stderr.puts(\"calls #{call_counter} handled #{handled_call_counter} submitted #{submitted_call_counter}\"\\\n                     \"delta  #{handled_call_counter - old_handled_call_counter} time #{Time.now - @time}\")\n        @old_handled_call_counter = handled_call_counter\n        @time = Time.now\n      end\n    end\n\n    def on_handled_return\n      @handled_call_counter += 1\n    end\n\n    private\n\n    attr_accessor :submitted_call_counter\n    attr_accessor :handled_call_counter\n    attr_accessor :old_handled_call_counter\n    attr_accessor :call_counter\n    attr_accessor :enable_debug\n\n  end\n\n\n  class TypeTracker\n    include Singleton\n\n    def initialize\n      ArgScanner.init(ENV['ARG_SCANNER_PIPE_FILE_PATH'], ENV['ARG_SCANNER_BUFFERING'],\n                      ENV['ARG_SCANNER_PROJECT_ROOT'], ENV['ARG_SCANNER_CATCH_ONLY_EVERY_N_CALL'])\n\n      @enable_debug = ENV[\"ARG_SCANNER_DEBUG\"]\n      @performance_monitor = if @enable_debug then TypeTrackerPerformanceMonitor.new else nil end\n\n      TracePoint.trace(:call, &ArgScanner.method(:handle_call))\n\n      TracePoint.trace(:return, &ArgScanner.method(:handle_return))\n\n      error_msg = ArgScanner.check_if_arg_scanner_ready()\n      if error_msg != nil\n        STDERR.puts error_msg\n        Process.exit(1)\n      end\n\n      ObjectSpace.define_finalizer(self, proc { ArgScanner.destructor() })\n    end\n\n    attr_accessor :enable_debug\n    attr_accessor :performance_monitor\n    attr_accessor :prefix\n\n  end\nend\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/version.rb",
    "content": "module ArgScanner\n  VERSION = \"0.3.3\"\nend\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner/workspace.rb",
    "content": "module ArgScanner\n  class Workspace\n\n    def initialize\n      @dir = ENV[\"ARG_SCANNER_DIR\"] || \".\"\n      @pid_file = @dir+\"/#{Process.pid}.pid\"\n    end\n\n    def on_process_start\n      File.open(@pid_file, \"w\") {}\n    end\n\n\n    def open_output_json(prefix)\n      path = @dir + \"/#{prefix}-#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}-#{Process.pid}.json\"\n      path_tmp_name = path + \".temp\"\n      File.open(path_tmp_name, \"w\") { |file| yield file }\n      require 'fileutils'\n      FileUtils.mv(path_tmp_name, path)\n    end\n\n    def on_process_exit\n      require 'fileutils'\n      FileUtils.rm(@pid_file)\n    end\n\n  end\nend\n"
  },
  {
    "path": "arg_scanner/lib/arg_scanner.rb",
    "content": "require \"arg_scanner/version\"\nrequire \"arg_scanner/arg_scanner\"\nrequire \"arg_scanner/type_tracker\"\nrequire \"arg_scanner/state_tracker\"\n\nmodule ArgScanner\n  # Your code goes here...\nend\n"
  },
  {
    "path": "arg_scanner/test/helper.rb",
    "content": "$LOAD_PATH.unshift(File.dirname(__dir__) + '/../lib')\nrequire \"test-unit\"\nrequire \"arg_scanner\"\n\nclass TestTypeTracker\n  include Singleton\n\n  attr_reader :last_args_info\n  attr_reader :last_call_info\n\n  def initialize\n    @tp = TracePoint.new(:call, :return) do |tp|\n      case tp.event\n        when :call\n          ArgScanner.handle_call(tp)\n\n          @last_args_info = ArgScanner.get_args_info.split ';'\n          @last_call_info = ArgScanner.get_call_info\n        when :return\n          ArgScanner.handle_return(tp)\n      end\n    end\n  end\n\n  def enable(*args, &b)\n    @tp.enable *args, &b\n  end\n\n  def signatures\n    Thread.current[:signatures] ||= Array.new\n  end\n\nend"
  },
  {
    "path": "arg_scanner/test/test_args_info.rb",
    "content": "#!/usr/bin/env ruby\nrequire File.expand_path(\"helper\", File.dirname(__FILE__))\nrequire 'date'\n\nclass TestArgsInfoWrapper\n\n  def foo(a); end\n\n  def foo2(a, b = 1); end\n\n  def foo3(**rest); end\n\n  def foo4(kw: :symbol, **rest1); end\n\n  def foo5(kw:, **rest); end\n\n  def foo6(a, *rest, b); end\n\n  def initialize\n\n    # @trace = TracePoint.new(:call) do |tp|\n    #   case tp.event\n    #     when :call\n    #       tp.binding.local_variables.each { |v| p tp.binding.eval v.to_s }\n    #       ArgScanner.handle_call(tp.lineno, tp.method_id, tp.path)\n    #       @args_info = ArgScanner.get_args_info\n    #       p @args_info\n    #   end\n    # end\n  end\nend\n\nclass TestArgsInfo < Test::Unit::TestCase\n\n  # @!attribute [r] type_tracker\n  #   @return [TestTypeTracker]\n  attr_reader :type_tracker\n\n\n  def setup\n    @args_info_wrapper = TestArgsInfoWrapper.new\n    @type_tracker = TestTypeTracker.instance\n  end\n\n  def teardown\n\n  end\n\n  def test_simple_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo3(a: Date.new, kkw: 'hi')\n    end\n\n    assert_equal [\"KEYREST,Date,a\", \"KEYREST,String,kkw\"], type_tracker.last_args_info\n  end\n\n  def test_empty_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo3()\n    end\n\n    assert_equal [], type_tracker.last_args_info\n  end\n\n  def test_req_and_opt_arg\n    type_tracker.enable do\n      @args_info_wrapper.foo2(Date.new)\n    end\n\n    assert_equal \"REQ,Date,a\", type_tracker.last_args_info[0]\n    assert type_tracker.last_args_info[1] == \"OPT,Fixnum,b\" || type_tracker.last_args_info[1] == \"OPT,Integer,b\"\n  end\n\n  def test_optkw_and_empty_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo4(kw: Date.new)\n    end\n\n    assert_equal [\"KEY,Date,kw\"], type_tracker.last_args_info\n  end\n\n  def test_reqkw_and_empty_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo5(kw: Date.new)\n    end\n\n    assert_equal [\"KEYREQ,Date,kw\"], type_tracker.last_args_info\n  end\n\n  def test_reqkw_and_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo5(kw: Date.new, aa: true, bb: '1')\n    end\n\n    assert_equal [\"KEYREQ,Date,kw\", \"KEYREST,TrueClass,aa\", \"KEYREST,String,bb\"], type_tracker.last_args_info\n  end\n\n  def test_optkw_and_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo4(aa: :symbol, bb: '1')\n    end\n\n    assert_equal [\"KEYREST,Symbol,aa\", \"KEYREST,String,bb\"], type_tracker.last_args_info\n  end\n\n  def test_optkw_passed_and_kwrest\n    type_tracker.enable do\n      @args_info_wrapper.foo4(kw: 'bla-bla', aa: :symbol, bb: '1')\n    end\n\n    assert_equal [\"KEY,String,kw\", \"KEYREST,Symbol,aa\", \"KEYREST,String,bb\"], type_tracker.last_args_info\n  end\n\n  def test_rest\n    type_tracker.enable do\n      @args_info_wrapper.foo6(1, 'hi', Date.new, '1')\n    end\n\n    assert type_tracker.last_args_info[0] == \"REQ,Fixnum,a\" || type_tracker.last_args_info[0] == \"REQ,Integer,a\"\n    assert type_tracker.last_args_info[1] == \"REST,Array,rest\"\n    assert type_tracker.last_args_info[2] == \"POST,String,b\"\n  end\n\n  def test_empty_rest\n    type_tracker.enable do\n      @args_info_wrapper.foo6(1, '1')\n    end\n\n    assert type_tracker.last_args_info[0] == \"REQ,Fixnum,a\" || type_tracker.last_args_info[0] == \"REQ,Integer,a\"\n    assert type_tracker.last_args_info[1] == \"REST,Array,rest\"\n    assert type_tracker.last_args_info[2] == \"POST,String,b\"\n  end\nend\n"
  },
  {
    "path": "arg_scanner/test/test_call_info.rb",
    "content": "#!/usr/bin/env ruby\nrequire File.expand_path(\"helper\", File.dirname(__FILE__))\n\nclass TestCallInfoWrapper\n\n  def sqr(z1 = 10, z2 = 11, z3 = 13, z4 = 14, z5, z6, z7, z8, y: '0', x: \"40\")\n\n  end\n\n  def sqr2(z0, z1 = 2, z2 = 10, z3 = 2, z4 = 0, y: 1, x: 30, z: '40')\n\n  end\n\n  def foo(a, b, c, *d, e)\n\n  end\n\n  def foo2(*args)\n\n  end\n\n  def foo3(b: 2, c: '3', **args)\n\n  end\n\n  def foo4(b: 2, c:, d: \"1\", dd: 1, ddd: '111', **args)\n\n  end\n\n  def foo5(b)\n\n  end\n\nend\n\nclass TestCallInfo < Test::Unit::TestCase\n\n  # @!attribute [r] type_tracker\n  #   @return [TestTypeTracker]\n  attr_reader :type_tracker\n\n  def setup\n    @call_info_wrapper = TestCallInfoWrapper.new\n    @type_tracker = TestTypeTracker.instance\n  end\n\n  def teardown\n\n  end\n\n  def test_simple\n    type_tracker.enable do\n      @call_info_wrapper.sqr2(10, 11)\n    end\n\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 2\n    #assert type_tracker.last_call_info[0] == \"sqr2\"\n    assert_equal 2, type_tracker.last_call_info[0]\n  end\n\n  def test_simple_req_arg\n    type_tracker.enable do\n      @call_info_wrapper.foo5(10)\n    end\n\n    assert_nil type_tracker.last_call_info\n  end\n\n  def test_simple_kw\n    type_tracker.enable do\n      @call_info_wrapper.sqr2(10, 11, x: 10, y: 1)\n    end\n\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 3\n    #assert type_tracker.last_call_info[0] == \"sqr2\"\n    assert_equal 4, type_tracker.last_call_info[0]\n    assert_equal \"x,y\", type_tracker.last_call_info[1]\n  end\n\n  def test_rest\n    type_tracker.enable do\n      @call_info_wrapper.foo2(1, 2, 3, 4, 5, 6, 7, 8)\n    end\n\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 2\n    #assert type_tracker.last_call_info[0] == \"foo2\"\n    assert_equal 8, type_tracker.last_call_info[0]\n  end\n\n  def test_post_and_rest\n    type_tracker.enable do\n      @call_info_wrapper.foo(1, 2, 3, 4, 5, 6, 7, 8)\n    end\n\n    #coz it is obvious that all the arguments were passed (they are all required)\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 2\n    #assert type_tracker.last_call_info[0] == \"foo\"\n    #assert type_tracker.last_call_info[0] == 8\n  end\n\n  def test_kwrest\n    type_tracker.enable do\n      @call_info_wrapper.foo3(a: 1, b: 2, c: 3, d: 4)\n    end\n\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 3\n    #assert type_tracker.last_call_info[0] == \"foo3\"\n    assert_equal 4, type_tracker.last_call_info[0]\n    assert_equal \"a,b,c,d\", type_tracker.last_call_info[1]\n  end\n\n  def test_rest_and_reqkw_args\n    type_tracker.enable do\n      @call_info_wrapper.foo4(b: \"hello\", c: 'world', e: 1, f: \"not\")\n    end\n\n    assert_not_nil type_tracker.last_call_info\n    #assert type_tracker.last_call_info.size == 3\n    #assert type_tracker.last_call_info[0] == \"foo4\"\n    assert_equal 4, type_tracker.last_call_info[0]\n    assert_equal \"b,c,e,f\", type_tracker.last_call_info[1]\n\n  end\nend"
  },
  {
    "path": "arg_scanner/test/test_state_tracker.rb",
    "content": "require 'test/unit'\nrequire 'tempfile'\nrequire 'fileutils'\nrequire 'json'\n\nclass StateTrackerTest < Test::Unit::TestCase\n\n  class << self\n    #Runs only once at start\n    def startup\n      file = Tempfile.new(\"StateTracker\")\n      dirname = file.path\n      FileUtils.rm(dirname)\n      file.close\n      begin\n        FileUtils.makedirs(dirname)\n        system(\"echo exit | ARG_SCANNER_DIR=\\\"#{dirname}\\\" ARG_SCANNER_ENABLE_STATE_TRACKER=\\\"1\\\" irb -r\\\"#{File.dirname(__dir__)}/lib/arg_scanner/starter.rb\\\"  2> /dev/null\")\n        files = Dir[\"#{dirname}/*.json\"]\n        @@json = JSON.parse(File.read(files[0]))\n      ensure\n        FileUtils.rm_rf(dirname)\n      end\n    end\n  end\n\n  def test_has_struct\n    assert_not_nil(get_class_with_name(\"Struct\"))\n  end\n\n  def test_symbol_is_fine\n    symbol = get_class_with_name(\"Symbol\")\n    assert_not_nil(symbol)\n    assert_equal(symbol[\"type\"], \"Class\")\n    assert_equal(symbol[\"superclass\"], \"Object\")\n    assert_not_nil(symbol[\"singleton_class_ancestors\"].find_index(\"Kernel\"))\n    assert_not_nil(symbol[\"ancestors\"].find_index(\"Comparable\"))\n    assert_not_nil(get_class_method(symbol, \"all_symbols\"))\n    assert_not_nil(get_instance_method(symbol, \"match\"))\n    parameters = get_instance_method(symbol, \"match\")['parameters']\n    assert_not_nil(parameters)\n    assert_equal(parameters[0][0], (RUBY_VERSION < \"2.4.0\") ?  \"req\" : \"rest\")\n  end\n\n  def test_loaded_path_is_fine\n    assert_not_nil(@@json[\"load_path\"])\n    assert_not_nil(@@json[\"load_path\"][0])\n  end\n\n  def test_constant_is_fine\n    assert_not_nil(@@json[\"top_level_constants\"])\n    assert_not_nil(@@json[\"top_level_constants\"][0])\n    assert_not_nil(@@json[\"top_level_constants\"][0][\"name\"])\n    assert_not_nil(@@json[\"top_level_constants\"][0][\"class_name\"])\n    assert_not_nil(@@json[\"top_level_constants\"][0][\"extended\"])\n  end\n\n  private\n\n  def get_class_method(symbol, name)\n    get_named_entity(symbol, \"class_methods\", name)\n  end\n\n  def get_instance_method(symbol, name)\n    get_named_entity(symbol, \"instance_methods\", name)\n  end\n\n  def get_class_with_name(name)\n    get_named_entity(@@json, \"modules\", name)\n  end\n\n  def get_named_entity(obj, index, name)\n    obj[index].find {|entity| entity[\"name\"] == name}\n  end\n\nend\n"
  },
  {
    "path": "arg_scanner/util/state_filter.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'json'\nrequire 'set'\n\nif ARGV.length < 3\n  puts(\"state_filter.rb <in-file> <out-file> [<list-of-names]\")\n  exit\nend\n\njson = JSON.parse(File.read(ARGV[0]))\n\nmodules2names = {}\n\njson[\"modules\"].each {|mod| modules2names[mod[\"name\"]] = mod}\n\nvisited = Set.new\nqueue = Queue.new\nARGV[2..-1].each do |it|\n  visited.add(it)\n  queue.push(it)\nend\n\nuntil queue.empty? do\n  elem = modules2names[queue.pop] || next\n  (elem[\"singleton_class_included\"] + elem[\"included\"] + [elem[\"superclass\"]]).each do |mod|\n    queue.push(mod) if visited.add?(mod)\n  end\nend\n\noutput_modules = visited.map do |mod|\n  modules2names[mod]\nend.compact\n\nFile.write(ARGV[1], JSON.pretty_generate({:modules => output_modules, :load_path => json[\"load_path\"]}))\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath \"com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7\"\n        classpath 'org.apache.httpcomponents:httpclient:4.5.2'\n    }\n}\n\nallprojects {\n    repositories {\n        mavenCentral()\n        maven {\n            url 'https://dl.bintray.com/kotlin/exposed'\n        }\n    }\n\n    apply plugin: 'java'\n    apply plugin: 'kotlin'\n\n    def project = it\n    dependencies {\n        if (project.name != 'ide-plugin') {\n            compile 'org.jetbrains:annotations:15.0'\n            compile \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n            compile \"org.jetbrains.kotlin:kotlin-reflect:$kotlin_version\"\n        }\n\n        testCompile 'junit:junit:4.12'\n        testCompile 'com.h2database:h2:1.4.193'\n    }\n\n    compileKotlin {\n        kotlinOptions.jvmTarget = \"1.8\"\n    }\n\n    test {\n        systemProperties System.properties\n        testLogging {\n            exceptionFormat = 'full'\n        }\n    }\n}\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '4.10.2'\n}\n\nsubprojects {\n    if (it.name in ['storage-server-api', 'lambda-update-handler', 'lambda-put-handler', 'contract-creator', 'state-tracker', 'ide-plugin']) {\n        dependencies {\n            compile 'com.google.code.gson:gson:2.8.0'\n        }\n    }\n}\n\n"
  },
  {
    "path": "common/build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n    }\n\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\ndependencies {\n}\n\nsourceSets {\n    main.java.srcDirs = ['src/main/java']\n    main.kotlin.srcDirs = ['src/main/java']\n\n    test.kotlin.srcDirs = ['src/test/java']\n}\n"
  },
  {
    "path": "common/src/main/java/org/jetbrains/ruby/codeInsight/Injector.kt",
    "content": "package org.jetbrains.ruby.codeInsight\n\n/**\n * Dependency injection mechanism\n */\ninterface Injector {\n    fun <T> getLogger(cl: Class<T>): Logger\n}\n\n@Volatile\nprivate var _injector: Injector? = null\nval injector: Injector\n    get() {\n        return _injector ?: throw IllegalStateException(\"Injector must be initialized before any usage\")\n    }\n\n// Because the we don't know anything about injector initializators we assume that it can be\n// potentially multi threaded but necessity of injector initialization thread safety isn't really investigated\n@Synchronized\nfun initInjector(injector: Injector) {\n    check(_injector == null) {\n        \"Injector must be initialized only once\"\n    }\n    _injector = injector\n}\n"
  },
  {
    "path": "common/src/main/java/org/jetbrains/ruby/codeInsight/Logger.kt",
    "content": "package org.jetbrains.ruby.codeInsight\n\ninterface Logger {\n    fun info(msg: String)\n}\n"
  },
  {
    "path": "common/src/main/java/org/jetbrains/ruby/codeInsight/PrintToStdoutLogger.kt",
    "content": "package org.jetbrains.ruby.codeInsight\n\nimport java.text.SimpleDateFormat\nimport java.util.*\n\nprivate val format = SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")\n\n/**\n * Most basic [Logger] implementation\n */\nclass PrintToStdoutLogger(private val category: String) : Logger {\n    constructor(cl : Class<*>) : this(cl.name)\n\n    override fun info(msg: String) {\n        println(\"${format.format(Calendar.getInstance())} [$category] $msg\")\n    }\n}\n"
  },
  {
    "path": "contract-creator/build.gradle",
    "content": "sourceSets {\n    main.java.srcDirs = ['src']\n}\n\ndependencies {\n    compile project(':common')\n    compile project(':ruby-call-signature')\n    compile project(':storage-server-api')\n\n//    compile 'com.h2database:h2:1.4.193'\n}\n\ntask runServer(type: JavaExec) {\n    classpath sourceSets.main.runtimeClasspath\n    main = 'org.jetbrains.ruby.runtime.signature.server.SignatureServerKt'\n}\n"
  },
  {
    "path": "contract-creator/src/org/jetbrains/ruby/runtime/signature/server/SignatureServer.kt",
    "content": "package org.jetbrains.ruby.runtime.signature.server\n\nimport com.google.gson.Gson\nimport com.google.gson.JsonParseException\nimport com.google.gson.JsonSyntaxException\nimport org.jetbrains.ruby.codeInsight.initInjector\nimport org.jetbrains.ruby.codeInsight.types.signature.CallInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\nimport org.jetbrains.ruby.runtime.signature.server.serialisation.ServerResponseBean\nimport org.jetbrains.ruby.runtime.signature.server.serialisation.toCallInfo\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.IOException\nimport java.nio.file.Paths\nimport java.util.*\nimport java.util.concurrent.ArrayBlockingQueue\nimport java.util.concurrent.atomic.AtomicBoolean\nimport java.util.concurrent.atomic.AtomicLong\nimport java.util.logging.Logger\nimport kotlin.concurrent.thread\n\nprivate const val EXIT_COMMAND = \"EXIT\";\n\nfun main(args: Array<String>) {\n    initInjector(SignatureServerInjector)\n    parseArgs(args).let {\n        DatabaseProvider.connectToDB(it.dbFilePath, isDefaultDatabase = true)\n    }\n\n    val pipeFileName = SignatureServer().runServerAsync(isDaemon = false)\n    println(\"Pass this to arg-scanner via --pipe-file-path: $pipeFileName\")\n\n    // Intercept Ctrl+C\n    Runtime.getRuntime().addShutdownHook(thread(start = false) {\n        File(pipeFileName).delete()\n    })\n}\n\nprivate data class ParsedArgs(val dbFilePath: String)\n\nprivate fun parseArgs(args: Array<String>): ParsedArgs {\n    if (args.size != 1) {\n        System.err.println(\"\"\"\n                One argument required: path-to-h2-db-file\n                Or if you run it via gradle: ./gradlew contract-creator:runServer --args path-to-db\n            \"\"\".trimIndent())\n        System.exit(1)\n    }\n    return ParsedArgs(args.single())\n}\n\nclass SignatureServer {\n    companion object {\n        private const val LOCAL_STORAGE_SIZE_LIMIT = 128\n\n        @Suppress(\"ObjectPropertyName\")\n        private val _runningServers: MutableList<SignatureServer> = Collections.synchronizedList(mutableListOf())\n        val runningServers: List<SignatureServer>\n            get() = _runningServers\n    }\n    private val LOGGER = Logger.getLogger(\"SignatureServer\")\n\n    private val callInfoContainer = LinkedList<CallInfo>()\n\n    private val gson = Gson()\n    private val queue = ArrayBlockingQueue<String>(10024)\n    private val isReady = AtomicBoolean(true)\n    private var previousPollEndedWithFlush = false\n\n    val readTime = AtomicLong(0)\n    val jsonTime = AtomicLong(0)\n    val addTime = AtomicLong(0)\n\n    private val signatureHandler = SignatureHandler()\n    private val pollJsonThread = PollJsonThread()\n\n    fun isProcessingRequests() = !isReady.get()\n\n    private fun generateTempFilePath(prefix: String = \"\"): String {\n        val dirForTempFiles = System.getProperty(\"java.io.tmpdir\")\n        return Paths.get(dirForTempFiles, prefix + UUID.randomUUID()).toString()\n    }\n\n    /**\n     * @return pipe filename path which should be passed to arg-scanner\n     */\n    fun runServerAsync(isDaemon: Boolean): String {\n        isReady.set(false)\n        _runningServers.add(this)\n        LOGGER.info(\"Starting server\")\n\n        val pipeFileName = generateTempFilePath(prefix = \"ruby-type-inference-pipe-\")\n        val proc: Process = Runtime.getRuntime().exec(\"mkfifo $pipeFileName\")\n        if (proc.waitFor() != 0) {\n            throw RuntimeException(\"Cannot create pipe file\")\n        }\n\n        signatureHandler.pipeFilePath = pipeFileName\n        signatureHandler.isDaemon = isDaemon\n        signatureHandler.start()\n\n        pollJsonThread.isDaemon = isDaemon\n        pollJsonThread.start()\n        return pipeFileName\n    }\n\n    var afterFlushListener: (() -> Unit)? = null\n\n    var afterExitListener: (() -> Unit)? = null\n\n    /**\n     * @return true when client won't send data anymore\n     */\n    private fun pollJson(): Boolean {\n        val jsonString by lazy { if (previousPollEndedWithFlush) queue.take() else queue.poll() }\n        if (callInfoContainer.size > LOCAL_STORAGE_SIZE_LIMIT || jsonString == null || jsonString == EXIT_COMMAND) {\n            flushNewTuplesToMainStorage()\n            previousPollEndedWithFlush = true\n            return jsonString == EXIT_COMMAND\n        }\n        previousPollEndedWithFlush = false\n\n        parseJson(jsonString)\n        return false\n    }\n\n    private fun parseJson(jsonString: String) {\n        val currCallInfo = ben(jsonTime) {\n            try {\n                return@ben gson.fromJson(jsonString, ServerResponseBean::class.java)?.toCallInfo()\n            } catch (ex: Throwable) {\n                when (ex) {\n                    is JsonSyntaxException, is JsonParseException -> {\n                        // Sometimes it's possible that some json fields contain quotation mark and we got JsonSyntaxException\n                        LOGGER.severe(\"Cannot parse: $jsonString\")\n                    }\n                    is IllegalStateException -> {\n                        LOGGER.severe(ex.message)\n                    }\n                    else -> throw ex\n                }\n                return@ben null\n            }\n        }\n\n        // filter, for example, such things #<Class:DidYouMean::Jaro>\n        if (currCallInfo?.methodInfo?.classInfo?.classFQN?.startsWith(\"#<\") == true) {\n            return\n        }\n\n        if (currCallInfo != null) {\n            ben(addTime) { callInfoContainer.add(currCallInfo) }\n        }\n    }\n\n    private fun flushNewTuplesToMainStorage() {\n        DatabaseProvider.defaultDatabaseTransaction {\n            for (callInfo in callInfoContainer) {\n                CallInfoTable.insertInfoIfNotContains(callInfo)\n            }\n        }\n        callInfoContainer.clear()\n        afterFlushListener?.invoke()\n    }\n\n    private inner class SignatureHandler internal constructor() : Thread() {\n        var pipeFilePath: String = \"\"\n\n        override fun run() {\n            try {\n                var missed = 0\n                var br = FileInputStream(pipeFilePath).bufferedReader()\n                var currString: String? = \"\"\n                do {\n                    // continue when EOF is reached because EOF doesn't mean that program\n                    // traced by arg-scanner is died. Program could simply call `Kernel.exec`\n                    // See CallStatCompletionTest.testRubyExecWithBuffering and\n                    // CallStatCompletionTest.testRubyExecWithoutBuffering\n                    currString = ben(readTime) { br.readLine() }\n\n                    if (currString != null) {\n                        queue.put(currString)\n                    } else {\n                        missed++\n                        br.close()\n                        // If don't reassign reader then `readLine` will always return `null`\n                        br = FileInputStream(pipeFilePath).bufferedReader()\n                    }\n\n                    // 1000 is just threshold for safety\n                } while (currString != EXIT_COMMAND && missed < 1000)\n            } catch (e: IOException) {\n                LOGGER.severe(\"Error in SignatureHandler\")\n            } finally {\n                File(pipeFilePath).delete()\n            }\n        }\n    }\n\n    private inner class PollJsonThread : Thread() {\n        override fun run() {\n            while (true) {\n                if (pollJson()) {\n                    isReady.set(true)\n                    afterExitListener?.invoke()\n                    _runningServers.remove(this@SignatureServer)\n                    break\n                }\n            }\n        }\n    }\n}\n\nfun <T> ben(x: AtomicLong, F: ()->T): T {\n    val start = System.nanoTime()\n    try {\n        return F.invoke()\n    }\n    finally {\n        x.addAndGet(System.nanoTime() - start)\n    }\n}"
  },
  {
    "path": "contract-creator/src/org/jetbrains/ruby/runtime/signature/server/SignatureServerInjector.kt",
    "content": "package org.jetbrains.ruby.runtime.signature.server\n\nimport org.jetbrains.ruby.codeInsight.Injector\nimport org.jetbrains.ruby.codeInsight.Logger\nimport org.jetbrains.ruby.codeInsight.PrintToStdoutLogger\n\nobject SignatureServerInjector : Injector {\n    override fun <T> getLogger(cl: Class<T>): Logger {\n        return PrintToStdoutLogger(cl)\n    }\n}\n"
  },
  {
    "path": "contract-creator/src/org/jetbrains/ruby/runtime/signature/server/serialisation/ServerResponseBean.kt",
    "content": "package org.jetbrains.ruby.runtime.signature.server.serialisation\n\nimport org.jetbrains.ruby.codeInsight.types.signature.*\n\ndata class ServerResponseBean(\n        val method_name: String,\n        /**\n         * Number of unnamedArguments passed by user explicitly\n         *\n         * For example for method:\n         * def foo(a, b = 1); end\n         *\n         * This method invocation have only one explicit argument\n         * foo(4)\n         *\n         * But this method invocation have two explicit unnamedArguments\n         * foo(4, 5)\n         */\n        val call_info_argc: Int,\n        val args_info: String,\n        val visibility: String,\n        val path: String,\n        val lineno: Int,\n        val receiver_name: String,\n        val return_type_name: String)\n\n// explicit here means that this unnamedArguments was explicitly provided by user\n// for example:\n// def foo(a, b = 1); end\n// foo(1)    # here only `a` is explicitly provided\n// foo(1, 5) # here `a` and `b` are both explicitly provided\nprivate data class Arg(val paramInfo: ParameterInfo, val type: String, var explicit: Boolean)\n\nprivate const val PARAMETER_MODIFIER_INDEX_IN_ATTRIBUTES = 0\nprivate const val PARAMETER_TYPE_INDEX_IN_ATTRIBUTES = 1\nprivate const val PARAMETER_NAME_INDEX_IN_ATTRIBUTES = 2\nprivate const val NUMBER_OF_ATTRIBUTES_FOR_PARAMETER = 3\n\n/**\n * @throws IllegalStateException if [ServerResponseBean] is not correctly formed\n */\nfun ServerResponseBean.toCallInfo(): CallInfo {\n    var argc = this.call_info_argc\n\n    val args = this.args_info.takeIf { it != \"\" }?.split(\";\")?.map {\n        val parts: List<String> = it.split(\",\")\n        val modifier = parts[PARAMETER_MODIFIER_INDEX_IN_ATTRIBUTES]\n        val type = parts[PARAMETER_TYPE_INDEX_IN_ATTRIBUTES]\n\n        val name = if (parts.size == NUMBER_OF_ATTRIBUTES_FOR_PARAMETER) {\n            // It's possible that parameter in ruby doesn't have name, for example:\n            // def foo(*); end\n            parts[PARAMETER_NAME_INDEX_IN_ATTRIBUTES]\n        } else {\n            \"\"\n        }\n\n        // If argc == -1 then all args are explicitly passed\n        return@map Arg(ParameterInfo(name, ParameterInfo.Type.valueOf(modifier)), type, explicit = argc == -1)\n    } ?: emptyList()\n\n    if (argc != -1) {\n        for (arg in args) {\n            if (arg.paramInfo.isNamedParameter ||\n                    arg.paramInfo.modifier == ParameterInfo.Type.REQ ||\n                    arg.paramInfo.modifier == ParameterInfo.Type.POST) {\n                arg.explicit = true\n                argc--\n            }\n        }\n\n        for (arg in args) {\n            if (argc <= 0) {\n                break\n            }\n            if (arg.paramInfo.modifier == ParameterInfo.Type.OPT) {\n                arg.explicit = true\n                argc--\n            }\n        }\n\n        for (arg in args) {\n            if (argc <= 0) {\n                break\n            }\n            if (arg.paramInfo.modifier == ParameterInfo.Type.REST) {\n                arg.explicit = true\n                argc--\n            }\n        }\n\n        check(argc == 0 || args.any { it.paramInfo.modifier == ParameterInfo.Type.BLOCK } && argc == 1) {\n            \"Failed to parse this bean: ${this.toString()}\"\n        }\n    }\n\n    val namedArgumentsNamesToTypes = args.asSequence().filter { it.paramInfo.isNamedParameter }\n            .map { ArgumentNameAndType(it.paramInfo.name, it.type) }.toList()\n\n    val unnamedArgumentsTypes = args.asSequence().filter { !it.paramInfo.isNamedParameter }\n            .map { arg ->\n                ArgumentNameAndType(arg.paramInfo.name, arg.type.takeIf { arg.explicit }\n                        ?: ArgumentNameAndType.IMPLICITLY_PASSED_ARGUMENT_TYPE)\n            }.toList()\n\n    val methodInfo = MethodInfo.Impl(\n            ClassInfo.Impl(gemInfoFromFilePathOrNull(this.path), this.receiver_name),\n            this.method_name,\n            RVisibility.valueOf(this.visibility),\n            Location(this.path, this.lineno))\n\n    return CallInfoImpl(methodInfo, namedArgumentsNamesToTypes, unnamedArgumentsTypes, this.return_type_name)\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Nov 07 19:25:40 MSK 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.10.2-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Available idea versions:\n# https://www.jetbrains.com/intellij-repository/releases\n# https://www.jetbrains.com/intellij-repository/snapshots\n\n# ruby plugin versions can be found here:\n# https://plugins.jetbrains.com/plugin/1293-ruby/versions\n\nkotlin_version=1.2.70\nideaVersion=IU-193.5233.102\nrubyPluginVersion=193.5233.57\nexposedVersion=0.17.3\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "ide-plugin/CHANGELOG.md",
    "content": "## 0.1.1 (15 Dec 2017)\n\n* (#17) Fix \"find usages\" action for dynamic symbols which resolve to text-based\n  definitions.\n\n## 0.1 (29 Nov 2017)\n\nInitial plugin version\n\n* Collect State action\n\n  Adds on_exit hook which dumps class/module includes structure and contained methods\n  which can be used for resolution/completion later. \n\n* Collect Type action\n\n  Enables call tracing (with a considerable slowdown) and dumps return types which\n  can be used for better type inference.\n\n* Symbol/Type provider to improve resolution and type inference based on the collected\n  data."
  },
  {
    "path": "ide-plugin/build.gradle",
    "content": "buildscript {\n    repositories {\n        maven { url 'https://dl.bintray.com/jetbrains/intellij-plugin-service' }\n    }\n}\n\nplugins {\n    id \"org.jetbrains.intellij\" version \"0.3.11\"\n}\n\ndependencies {\n    def withoutKotlinAndMySql = {\n        exclude group: 'org.jetbrains.kotlin'\n        exclude group: 'mysql'\n    }\n    def withoutSlfAndKotlinAndMySql = {\n        exclude group: 'org.slf4j'//, module: 'slf4j-api'\n        exclude group: 'org.jetbrains.kotlin'\n        exclude group: 'mysql'\n    }\n\n    compile project(':common')\n    compile project(':ruby-call-signature'), withoutKotlinAndMySql\n    compile project(':storage-server-api'), withoutSlfAndKotlinAndMySql\n    compile project(':contract-creator'), withoutSlfAndKotlinAndMySql\n    compile project(':state-tracker'), withoutSlfAndKotlinAndMySql\n\n    // https://mvnrepository.com/artifact/com.h2database/h2\n    compile group: 'com.h2database', name: 'h2', version: '1.4.199'\n\n}\n\nsourceSets {\n    main.java.srcDirs = ['src']\n    main.resources.srcDirs = ['resources']\n    test.java.srcDirs = ['src/test/java']\n    test.resources.srcDirs=['src/test/testData']\n}\n\nintellij {\n    version ideaVersion\n    pluginName 'ruby-runtime-stats'\n    plugins = [\"yaml\", \"org.jetbrains.plugins.ruby:$rubyPluginVersion\"]\n}\n\npatchPluginXml {\n    sinceBuild '193.5233.102'\n    untilBuild '193.*'\n    version '0.3.3'\n}\n\nprepareSandbox.doLast {\n    def destDir = \"$it.destinationDir/$intellij.pluginName\"\n    copy {\n        from sourceSets.main.resources.include(\"**/*.rb\", \"**/*.db\")\n        into destDir\n    }\n}\n\ntest {\n    testLogging.showStandardStreams = true\n}\n\n"
  },
  {
    "path": "ide-plugin/resources/META-INF/plugin.xml",
    "content": "<idea-plugin>\n    <id>org.jetbrains.ruby-runtime-stats</id>\n    <name>Ruby Dynamic Code Insight</name>\n    <vendor email=\"\" url=\"http://www.jetbrains.com\">JetBrains</vendor>\n    <depends>com.intellij.modules.ruby</depends>\n    <description><![CDATA[\n        <p>This plugin provides additional Code Insight intelligence to improve resolution, find usages and refactoring\n        capabilities.</p>\n\n        <p>The data is obtained via user project execution altered by a special tracker which stores symbol\n        hierarchy, method return types, etc.</p>\n    ]]></description>\n\n    <change-notes><![CDATA[\n        <a href=\"https://github.com/JetBrains/ruby-type-inference/blob/master/ide-plugin/CHANGELOG.md\">Changelog</a>\n    ]]>\n    </change-notes>\n\n    <applicationListeners>\n        <listener class=\"org.jetbrains.plugins.ruby.ruby.codeInsight.ProjectLifecycleListenerImpl\"\n                  topic=\"com.intellij.openapi.project.ProjectManagerListener\"/>\n        <listener class=\"org.jetbrains.plugins.ruby.ruby.codeInsight.RubyDynamicCodeInsightPluginAppLifecyctlListener\"\n                  topic=\"com.intellij.ide.AppLifecycleListener\"\n                  activeInHeadlessMode=\"true\"/>\n    </applicationListeners>\n\n    <extensions defaultExtensionNs=\"com.intellij\">\n        <executor implementation=\"com.intellij.execution.executors.RunWithTypeTrackerExecutor\"/>\n        <!--<executor implementation=\"com.intellij.execution.executors.CollectStateExecutor\"/>-->\n\n        <programRunner implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.types.RubyRunWithTypeTrackerRunner\"/>\n        <programRunner implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.types.RubyCollectStateRunner\"/>\n\n        <projectService serviceImplementation=\"org.jetbrains.plugins.ruby.settings.RubyTypeContractsSettings\"/>\n\n        <intentionAction>\n            <className>org.jetbrains.plugins.ruby.ruby.intentions.AddContractAnnotationIntention</className>\n        </intentionAction>\n\n        <intentionAction>\n            <className>org.jetbrains.plugins.ruby.ruby.intentions.RemoveCollectedInfoIntention</className>\n        </intentionAction>\n\n        <postStartupActivity implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.TrackerDataLoader\"/>\n\n        <applicationConfigurable groupId=\"language\"\n                                 groupWeight=\"130\"\n                                 instance=\"org.jetbrains.plugins.ruby.settings.RubyTypeContractsConfigurable\"/>\n\n    </extensions>\n\n    <extensions defaultExtensionNs=\"org.jetbrains.plugins.ruby\">\n\n        <rubyTypeProvider implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.types.RubyParameterTypeProvider\"/>\n        <symbolicTypeInferenceProvider implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.types.ReturnTypeSymbolicTypeInferenceProvider\"/>\n\n        <symbolProvider implementation=\"org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker.ClassHierarchySymbolProvider\"/>\n\n        <runConfigurationExtension\n                implementation=\"org.jetbrains.plugins.ruby.ruby.run.configuration.RunWithTypeTrackerRunConfigurationExtension\"/>\n    </extensions>\n\n    <actions>\n        <group id=\"ruby.contracts.group\"\n               text=\"Type Contracts\"\n               popup=\"true\">\n            <add-to-group group-id=\"RUBY_TOOLS\" anchor=\"before\" relative-to-action=\"BUNDLER_ACTIONS\"/>\n            <action class=\"org.jetbrains.plugins.ruby.ruby.actions.ExportContractsAction\"\n                    id=\"ruby.contracts.export\"\n                    text=\"Export type contracts\"/>\n            <action class=\"org.jetbrains.plugins.ruby.ruby.actions.ImportContractsAction\"\n                    id=\"ruby.contracts.import\"\n                    text=\"Import type contracts\"/>\n        </group>\n        <group id=\"ruby.ancestors_extractor.group\"\n               text=\"Export ancestors (for rails applications only!)\"\n               popup=\"true\" internal=\"true\">\n            <add-to-group group-id=\"RUBY_TOOLS\" anchor=\"before\" relative-to-action=\"BUNDLER_ACTIONS\"/>\n            <action class=\"org.jetbrains.plugins.ruby.ruby.actions.ExportAncestorsByObjectSpaceAction\"\n                    id=\"ruby.ancestors_extractor.export_by_objectspace\"\n                    text=\"Export ancestors by Ruby's objectspace\"/>\n            <action class=\"org.jetbrains.plugins.ruby.ruby.actions.ExportAncestorsByRubymineAction\"\n                    id=\"ruby.ancestors_extractor.export_by_rubymine\"\n                    text=\"Export ancestors by Rubymine\"/>\n            <action class=\"org.jetbrains.plugins.ruby.ruby.actions.ExportAncestorsDiffAction\"\n                    id=\"ruby.ancestors_extractor.diff\"\n                    text=\"Export ancestors diff\"/>\n        </group>\n    </actions>\n\n</idea-plugin>"
  },
  {
    "path": "ide-plugin/src/com/intellij/execution/executors/CollectStateExecutor.kt",
    "content": "package com.intellij.execution.executors\n\nimport com.intellij.execution.Executor\nimport com.intellij.icons.AllIcons\nimport com.intellij.openapi.util.text.StringUtil\nimport com.intellij.openapi.wm.ToolWindowId\nimport javax.swing.Icon\n\nclass CollectStateExecutor : Executor() {\n\n    private val myIcon = AllIcons.General.GearPlain\n\n    override fun getToolWindowId(): String {\n        return ToolWindowId.RUN\n    }\n\n    override fun getToolWindowIcon(): Icon {\n        return myIcon\n    }\n\n    override fun getIcon(): Icon {\n        return myIcon\n    }\n\n    override fun getDisabledIcon(): Icon? {\n        return null\n    }\n\n    override fun getDescription(): String {\n        return \"Run selected configuration with collecting state\"\n    }\n\n    override fun getActionName(): String {\n        return \"CollectState\"\n    }\n\n    override fun getId(): String {\n        return EXECUTOR_ID\n    }\n\n    override fun getStartActionText(): String {\n        return \"Run with Collecting State\"\n    }\n\n    override fun getContextActionId(): String {\n        return \"RunCollectState\"\n    }\n\n    override fun getHelpId(): String? {\n        return null\n    }\n\n    override fun getStartActionText(configurationName: String): String {\n        val name = escapeMnemonicsInConfigurationName(\n                StringUtil.first(configurationName, 30, true))\n        return \"Run\" + (if (StringUtil.isEmpty(name)) \"\" else \" '$name'\") + \" with Collecting State\"\n    }\n\n    private fun escapeMnemonicsInConfigurationName(configurationName: String): String {\n        return configurationName.replace(\"_\", \"__\")\n    }\n\n    companion object {\n        val EXECUTOR_ID = \"CollectState\"\n    }\n}"
  },
  {
    "path": "ide-plugin/src/com/intellij/execution/executors/RunWithTypeTrackerExecutor.java",
    "content": "package com.intellij.execution.executors;\n\nimport com.intellij.execution.Executor;\nimport com.intellij.icons.AllIcons;\nimport com.intellij.openapi.util.IconLoader;\nimport com.intellij.openapi.util.text.StringUtil;\nimport com.intellij.openapi.wm.ToolWindowId;\nimport com.intellij.util.ui.UIUtil;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport javax.swing.*;\nimport java.net.URL;\n\npublic class RunWithTypeTrackerExecutor extends Executor {\n    @NotNull\n    public static final String EXECUTOR_ID = \"RunWithTypeTracker\";\n\n    @NotNull\n    private final Icon myIcon;\n\n    public RunWithTypeTrackerExecutor() {\n        final URL iconURL = RunWithTypeTrackerExecutor.class.getClassLoader().getResource(\n                UIUtil.isUnderDarcula() ? \"runWithTypeTracker_dark.svg\" : \"runWithTypeTracker.svg\");\n        final Icon icon = IconLoader.findIcon(iconURL);\n        myIcon = icon != null ? icon : AllIcons.General.Error;\n    }\n\n    @Override\n    public String getToolWindowId() {\n        return ToolWindowId.RUN;\n    }\n\n    @Override\n    public Icon getToolWindowIcon() {\n        return myIcon;\n    }\n\n    @NotNull\n    @Override\n    public Icon getIcon() {\n        return myIcon;\n    }\n\n    @Nullable\n    @Override\n    public Icon getDisabledIcon() {\n        return null;\n    }\n\n    @NotNull\n    @Override\n    public String getDescription() {\n        return \"Run selected configuration with Type Tracker\";\n    }\n\n    @NotNull\n    @Override\n    public String getActionName() {\n        return \"Run with Type Tracker\";\n    }\n\n    @NotNull\n    @Override\n    public String getId() {\n        return EXECUTOR_ID;\n    }\n\n    @NotNull\n    public String getStartActionText() {\n        return \"Run with Type Tracker\";\n    }\n\n    @NotNull\n    @Override\n    public String getContextActionId() {\n        return \"Run with Type Tracker\";\n    }\n\n    @Nullable\n    @Override\n    public String getHelpId() {\n        return null;\n    }\n\n    @NotNull\n    @Override\n    public String getStartActionText(@NotNull final String configurationName) {\n        final String name = escapeMnemonicsInConfigurationName(\n                StringUtil.first(configurationName, 30, true));\n        return \"Run\" + (StringUtil.isEmpty(name) ? \"\" :  \" '\" + name + \"'\") + \" with Type Tracker\";\n    }\n\n    @NotNull\n    private static String escapeMnemonicsInConfigurationName(@NotNull final String configurationName) {\n        return configurationName.replace(\"_\", \"__\");\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/IdePluginLogger.kt",
    "content": "package org.jetbrains.plugins.ruby\n\nimport org.jetbrains.ruby.codeInsight.Logger\n\nclass IdePluginLogger(private val intellijPlatformLogger: com.intellij.openapi.diagnostic.Logger) : Logger {\n    override fun info(msg: String) {\n        intellijPlatformLogger.info(msg)\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/PluginResourceUtil.java",
    "content": "package org.jetbrains.plugins.ruby;\n\nimport com.intellij.ide.plugins.IdeaPluginDescriptor;\nimport com.intellij.ide.plugins.PluginManager;\nimport com.intellij.openapi.extensions.PluginId;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.File;\n\npublic final class PluginResourceUtil {\n    private static final String PLUGIN_ID = \"org.jetbrains.ruby-runtime-stats\";\n\n    private PluginResourceUtil() {\n    }\n\n    @NotNull\n    public static String getPluginResourcesPath() {\n        final IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId(PLUGIN_ID));\n        if (plugin == null) {\n            throw new AssertionError(\"Nonsense: this plugin is not registered\");\n        }\n        final File pluginHome = plugin.getPath();\n        if (pluginHome == null) {\n            throw new AssertionError(\"Corrupted plugin: could not find home\");\n        }\n        return pluginHome.getPath() + \"/\";\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/RubyDynamicCodeInsightPluginInjector.kt",
    "content": "package org.jetbrains.plugins.ruby\n\nimport org.jetbrains.ruby.codeInsight.Injector\nimport org.jetbrains.ruby.codeInsight.Logger\n\nobject RubyDynamicCodeInsightPluginInjector : Injector {\n    override fun <T> getLogger(cl: Class<T>): Logger {\n        return IdePluginLogger(com.intellij.openapi.diagnostic.Logger.getInstance(cl))\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ancestorsextractor/AncestorsExtractor.kt",
    "content": "package org.jetbrains.plugins.ruby.ancestorsextractor\n\nimport com.intellij.openapi.application.ReadAction\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport com.intellij.openapi.util.ThrowableComputable\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.SymbolUtil\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.util.SymbolHierarchy\nimport java.io.FileWriter\nimport java.io.PrintWriter\n\n/**\n * Keeps Ruby module [name] and it's [ancestors]\n */\ndata class RubyModule(val name: String, val ancestors: List<String>)\n\n/**\n * Ancestors extractor for Ruby's project's modules\n */\ninterface AncestorsExtractorBase {\n    /**\n     * Extract ancestors for every Ruby's Module in [project]\n     */\n    fun extractAncestors(project: Project, sdk: Sdk): List<RubyModule>\n\n    /**\n     * Set [RailsConsoleRunner.Listener] for [RailsConsoleRunner]\n     * @see RailsConsoleRunner.Listener\n     */\n    var listener: RailsConsoleRunner.Listener?\n}\n\n/**\n * Extract ancestors for Ruby's modules the way how RubyMine sees them.\n * If you don't provide [allModulesNames] this implementation works only for Ruby on Rails project as in case when\n * you don't provide [allModulesNames] all modules names would be taken from Ruby on Rails console (\"bin/rails console\")\n */\nclass AncestorsExtractorByRubyMine(private val allModulesNames: List<String>? = null,\n                                   override var listener: RailsConsoleRunner.Listener? = null) : AncestorsExtractorBase {\n    /**\n     * Implementation of [AncestorsExtractorBase.extractAncestors] based on how RubyMine sees ancestors\n     */\n    override fun extractAncestors(project: Project, sdk: Sdk): List<RubyModule> {\n        val allModulesNamesLocal: List<String> = allModulesNames ?: extractAllModulesNames(project, sdk)\n        // I don't know why but seems that SymbolScopeUtil#getAncestorsCaching needs to be called\n        // inside ReadAction otherwise sometimes I get Exception\n        return ReadAction.compute(ThrowableComputable<List<RubyModule>, Exception> {\n            allModulesNamesLocal.map { RubyModule(it, extractAncestorsFor(it, project)) }\n        })\n    }\n\n    /**\n     * Extract all modules names from Ruby on Rails project.\n     */\n    private fun extractAllModulesNames(project: Project, sdk: Sdk): List<String> {\n        val tempFile = createTempFile(prefix = \"modules\", suffix = \".json\")\n        try {\n            val rubyCode = \"\"\"\n                require 'json'\n                open(\"${tempFile.path}\", \"w\") do |f|\n                  f.puts JSON.generate(ObjectSpace.each_object(Module).to_a.map {|from| from.to_s})\n                end\n            \"\"\".trimIndent()\n            return RailsConsoleRunner(listener).extractFromRubyOnRailsConsole(project, sdk, Array<String>::class.java,\n                    tempFile.path, rubyCode, eagerLoad = true).toList()\n        } finally {\n            tempFile.delete()\n        }\n    }\n\n    private fun extractAncestorsFor(rubyModuleName: String, project: Project): List<String> {\n        return SymbolUtil.findConstantByFQN(project, rubyModuleName)?.let {\n            SymbolHierarchy.getAncestorsCaching(it, null)\n        }?.map { it.symbol.fqnWithNesting.toString() } ?: listOf()\n    }\n}\n\n/**\n * Extract ancestors the way Ruby's Module.ancestors method does this.\n * This implementation works only for Ruby on Rails project.\n * @see <a href=\"https://ruby-doc.org/core-2.1.0/Module.html#method-i-ancestors\">Ruby's Module.ancestors</a>\n */\nclass AncestorsExtractorByObjectSpace(override var listener: RailsConsoleRunner.Listener? = null) : AncestorsExtractorBase {\n    /**\n     * Implementation of [AncestorsExtractorBase.extractAncestors] based on Ruby's Module.ancestors method\n     * @see <a href=\"https://ruby-doc.org/core-2.1.0/Module.html#method-i-ancestors\">Ruby's Module.ancestors</a>\n     */\n    override fun extractAncestors(project: Project, sdk: Sdk): List<RubyModule> {\n        val tempFile = createTempFile(prefix = \"module-ancestors-pair\", suffix = \".json\")\n        try {\n            val rubyCode = \"\"\"\n                objects = ObjectSpace.each_object(Module).to_a; nil # nil is to prevent irb to print big objects output\n                objects = objects.map {|mod| {:name => mod.to_s, :ancestors => mod.ancestors.map {|from| from.to_s}}}; nil\n                require 'json'\n                open(\"${tempFile.path}\", \"w\") do |f|\n                  f.puts JSON.generate(objects)\n                end\n            \"\"\".trimIndent()\n            return RailsConsoleRunner(listener).extractFromRubyOnRailsConsole(project, sdk, Array<RubyModule>::class.java,\n                    tempFile.path, rubyCode, eagerLoad = true).toList()\n        } finally {\n            tempFile.delete()\n        }\n    }\n\n    /**\n     * Extract information about where ruby includes was performed\n     * @return Map where key is [String] with the following format: \"**ancestor**#**includer**\" and value is [String]\n     * containing ruby file path and line number where **ancestor** was included by **includer**\n     */\n    fun extractIncludes(project: Project, sdk: Sdk): Map<String, String> {\n        val tempWhereIncluded = createTempFile(prefix = \"where-included\", suffix = \".json\")\n        val tempRubyCodeFile = createTempFile(prefix = \"preload-temp-script\", suffix = \".rb\")\n        try {\n            PrintWriter(FileWriter(tempRubyCodeFile)).use {\n                it.println(\"\"\"\n                    END {\n                        require 'json'\n                        open(\"${tempWhereIncluded.path}\", \"w\") { |f| f.puts JSON.generate(RubyDetectIncludeUniqueModuleName.get) }\n                    }\n\n                    module RubyDetectIncludeUniqueModuleName\n                        @@map = {}\n                        def self.get\n                            return @@map\n                        end\n\n                        def append_features(mod)\n                            # self included by mod\n                            @@map[\"#{self.to_s}##{mod.to_s}\"] = caller_locations()[1].to_s\n                            super\n                        end\n                    end\n\n                    Module.prepend RubyDetectIncludeUniqueModuleName\n                \"\"\".trimIndent())\n            }\n            @Suppress(\"UNCHECKED_CAST\")\n            return RailsConsoleRunner(listener).extractFromRubyOnRailsConsole(project, sdk, Map::class.java,\n                    tempWhereIncluded.path, rubyCode = \"\", eagerLoad = true,\n                    rubyConsoleArguments = arrayOf(\"-r\", tempRubyCodeFile.path)) as Map<String, String>\n        } finally {\n            tempRubyCodeFile.delete()\n            tempWhereIncluded.delete()\n        }\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ancestorsextractor/RailsConsoleRunner.kt",
    "content": "package org.jetbrains.plugins.ruby.ancestorsextractor\n\nimport com.google.gson.Gson\nimport com.intellij.execution.ExecutionException\nimport com.intellij.execution.ExecutionModes\nimport com.intellij.execution.process.ProcessEvent\nimport com.intellij.execution.process.ProcessListener\nimport com.intellij.openapi.application.ReadAction\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport com.intellij.openapi.util.Key\nimport com.intellij.openapi.util.ThrowableComputable\nimport org.jetbrains.plugins.ruby.ancestorsextractor.RailsConsoleRunner.Listener\nimport org.jetbrains.plugins.ruby.rails.Rails3Constants\nimport org.jetbrains.plugins.ruby.rails.Rails4Constants\nimport org.jetbrains.plugins.ruby.ruby.RubyUtil\nimport org.jetbrains.plugins.ruby.ruby.run.context.RubyScriptExecutionContext\nimport java.io.File\nimport java.io.IOException\nimport java.io.PrintWriter\nimport java.nio.file.Paths\n\n/**\n * Runs some Ruby code on Ruby on Rails console (\"bin/rails console\")\n */\nclass RailsConsoleRunner(\n        /**\n         * Set [Listener]. There is only one possible [Listener]. Feel free to change it to\n         * addListener to have multiple listeners if you want\n         */\n        private var listener: RailsConsoleRunner.Listener?) {\n\n    data class RailsConsoleExecutionResult(val stdout: String, val stderr: String)\n\n    /**\n     * Extract information left by [rubyCode] in [tempJSONFilPath]\n     * @param clazz which kind of information [rubyCode] left in [tempJSONFilPath].\n     * Note: Do not use [List] here because [Gson] won't parse it, use [Array] instead\n     * @param tempJSONFilPath path to temp file where [rubyCode] left information which\n     * can be converted from JSON to [clazz]\n     * @param rubyCode Your ruby code which should leave some JSON information in [tempJSONFilPath]\n     * @param eagerLoad Works like you set `eager_load` variable inside config/environments/LOADED_ENVIRONMENT.rb\n     * @param rubyConsoleArguments additional arguments to pass to ruby interpreter\n     * @throws ExecutionException when error occurred either while executing [rubyCode] either\n     * while trying to read data from JSON left by Ruby\n     * @throws IllegalStateException when getter [Project.getBasePath] of [project] returns `null`\n     */\n    @Throws(ExecutionException::class, IllegalStateException::class)\n    fun <T> extractFromRubyOnRailsConsole(project: Project, sdk: Sdk, clazz: Class<T>, tempJSONFilPath: String,\n                                          rubyCode: String, eagerLoad: Boolean,\n                                          rubyConsoleArguments: Array<String> = arrayOf()): T {\n        val projectDirPath = project.basePath ?: throw IllegalStateException(\"Seems that project is default. \" +\n                \"Quote from com.intellij.openapi.project.Project#getBasePath JavaDoc\")\n\n        val rubyCodeToExec = if (eagerLoad) {\n            \"\"\"\n                Rails.application.eager_load!; nil # nil is to prevent irb to print big output\n\n            \"\"\".trimIndent() + rubyCode\n        } else {\n            rubyCode\n        }\n\n        val railsConsoleExecutionResult = runRailsConsole(projectDirPath, sdk,\n                rubyCodeToExec, rubyConsoleArguments, railsConsoleArguments = arrayOf(\"--environment=development\"))\n\n        val ret = ReadAction.compute(ThrowableComputable<T?, Exception> {\n            val file = File(tempJSONFilPath)\n            return@ThrowableComputable try {\n                file.inputStream().bufferedReader().use {\n                    Gson().fromJson(it.readLine(), clazz)\n                }\n            } catch (ex: IOException) {\n                null\n            }\n        })\n\n        listener?.informationWasExtractedFromIRB()\n\n        return ret ?: throw ExecutionException(\"\"\"\n            |Error occurred either in the following Ruby code (ruby was launched with these arguments: ${rubyConsoleArguments.contentToString()}):\n            |$rubyCodeToExec\n\n            |stdout of this Ruby code execution:\n            |${railsConsoleExecutionResult.stdout}\n\n            |stderr of this Ruby code execution:\n            |${railsConsoleExecutionResult.stderr}\n\n            |either while trying to read data from JSON left by Ruby\n        \"\"\".trimMargin())\n    }\n\n    /**\n     * Run [toExec] in ruby on rails console (\"bin/rails console\"). You can use it for example for generating\n     * some temp json files to later parse them in Kotlin/Java\n     * @param projectDirPath Path to project dir\n     * @param toExec Newline separated [String] to execute in ruby on rails console\n     * @param rubyConsoleArguments additional arguments to pass to ruby interpreter\n     * @param railsConsoleArguments additional arguments to pass to \"bin/rails console\"\n     * @throws ExecutionException when error occurred while launching rails console\n     */\n    @Throws(ExecutionException::class)\n    fun runRailsConsole(projectDirPath: String, sdk: Sdk, toExec: String,\n                        rubyConsoleArguments: Array<String> = arrayOf(),\n                        railsConsoleArguments: Array<String> = arrayOf()): RailsConsoleExecutionResult {\n        val executionMode = ExecutionModes.SameThreadMode(false)\n        executionMode.addProcessListener(object : ProcessListener {\n            override fun processTerminated(event: ProcessEvent) { }\n            override fun processWillTerminate(event: ProcessEvent, willBeDestroyed: Boolean) { }\n            override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) { }\n\n            override fun startNotified(event: ProcessEvent) {\n                PrintWriter(event.processHandler.processInput, true).use { it.println(toExec); it.println(\"quit\") }\n            }\n        })\n\n        val processOutput = RubyScriptExecutionContext.create(Paths.get(projectDirPath, Rails4Constants.CONSOLE4_SCRIPT).toString(), sdk)\n//                .withInterpreterOptions(*rubyConsoleArguments) todo API doesn't exist anymore :(\n                // todo replace with .withInterpreterOptions when API becomes available\n                .withAdditionalEnvs(mapOf(RubyUtil.RUBYOPT to rubyConsoleArguments.joinToString(separator = \" \")))\n                .withArguments(Rails3Constants.CONSOLE, *railsConsoleArguments)\n                .withExecutionMode(executionMode)\n                .withWorkingDirPath(projectDirPath).executeScript()\n                ?: throw ExecutionException(\"Error occurred while launching rails console\")\n\n        listener?.irbConsoleExecuted()\n\n        return RailsConsoleRunner.RailsConsoleExecutionResult(\n                processOutput.stdout,\n                processOutput.stderr\n        )\n    }\n\n    /**\n     * [Listener] of particular events in [RailsConsoleRunner].\n     */\n    interface Listener {\n        /**\n         * It would be called first\n         */\n        fun irbConsoleExecuted()\n\n        /**\n         * It would be called second\n         */\n        fun informationWasExtractedFromIRB()\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/actions/ExportAncestorsActions.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.actions\n\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorBase\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorByObjectSpace\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorByRubyMine\nimport org.jetbrains.plugins.ruby.ancestorsextractor.RubyModule\nimport java.io.PrintWriter\n\n/**\n * Base class representation for exporting Ruby on Rails project's modules' ancestors\n */\nabstract class ExportAncestorsActionBase(\n        whatToExport: String,\n        generateFilename: (Project) -> String,\n        private val extractor: AncestorsExtractorBase\n) : ExportFileActionBase(whatToExport, generateFilename, extensions = arrayOf(\"txt\"),\n        numberOfProgressBarFractions = 5) {\n\n    override fun backgroundProcess(absoluteFilePath: String, module: Module?, sdk: Sdk?, project: Project) {\n        moveProgressBarForward()\n        extractor.listener = ProgressListener()\n        val ancestors: List<RubyModule> = try {\n            extractor.extractAncestors(project, sdk ?: throw IllegalStateException(\"Ruby SDK is not set\"))\n        } catch(ex: Throwable) {\n            PrintWriter(absoluteFilePath).use {\n                it.println(ex.message)\n            }\n            return\n        }\n        moveProgressBarForward()\n        PrintWriter(absoluteFilePath).use { printWriter ->\n            ancestors.forEach {\n                printWriter.println(\"Module: ${it.name}\")\n                printWriter.print(\"Ancestors: \")\n                if (it.ancestors.isEmpty()) printWriter.print(\"Nothing found\")\n                it.ancestors.forEach { printWriter.print(\"$it \") }\n                printWriter.print(\"\\n\\n\")\n            }\n        }\n        moveProgressBarForward()\n    }\n}\n\nclass ExportAncestorsByObjectSpaceAction : ExportAncestorsActionBase(\n        whatToExport = \"ancestors by ObjectSpace\",\n        generateFilename = { project -> \"ancestors-by-objectspace-${project.name}\" },\n        extractor = AncestorsExtractorByObjectSpace()\n)\n\nclass ExportAncestorsByRubymineAction : ExportAncestorsActionBase(\n        whatToExport = \"ancestors by RubyMine\",\n        generateFilename = { project -> \"ancestors-by-rubymine-${project.name}\" },\n        extractor = AncestorsExtractorByRubyMine()\n)"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/actions/ExportAncesttorsDiffAction.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.actions\n\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorByObjectSpace\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorByRubyMine\nimport org.jetbrains.plugins.ruby.ancestorsextractor.RubyModule\nimport java.io.PrintWriter\n\nclass ExportAncestorsDiffAction : ExportFileActionBase(whatToExport = \"ancestors diff\",\n        generateFilename = { project: Project ->  \"ancestors-diff-${project.name}\" }, extensions = arrayOf(\"txt\"),\n        numberOfProgressBarFractions = 9) {\n    override fun backgroundProcess(absoluteFilePath: String, module: Module?, sdk: Sdk?, project: Project) {\n        moveProgressBarForward()\n        val byObjectSpace: List<RubyModule>\n        val byRubyMine: List<RubyModule>\n        val ancestorHashSymbolIncluderToWhereIncluded: Map<String, String>\n        try {\n            val listener = ProgressListener()\n            val ancestorsExtractorByObjectSpace = AncestorsExtractorByObjectSpace(listener)\n\n            // Here all listener methods would be called\n            byObjectSpace = ancestorsExtractorByObjectSpace.extractAncestors(project, sdk ?: throw IllegalStateException(\"Ruby SDK is not set\"))\n\n            // The second place where all listener methods would be called\n            ancestorHashSymbolIncluderToWhereIncluded = ancestorsExtractorByObjectSpace.extractIncludes(project, sdk)\n\n            // Provide all modulesNames same as in byObjectSpace for easy ancestors comparison\n            val allModulesNames: List<String> = byObjectSpace.map { it.name }\n\n            // The third place where all listener methods would be called\n            byRubyMine = AncestorsExtractorByRubyMine(allModulesNames, listener)\n                    .extractAncestors(project, sdk)\n        } catch (ex: Throwable) {\n            PrintWriter(absoluteFilePath).use {\n                it.println(ex.message)\n            }\n            return\n        }\n\n        moveProgressBarForward()\n        PrintWriter(absoluteFilePath).use { printWriter ->\n            val objectSpaceIterator = byObjectSpace.iterator()\n            val rubymineIterator = byRubyMine.iterator()\n            while (objectSpaceIterator.hasNext() && rubymineIterator.hasNext()) {\n                val a = objectSpaceIterator.next()\n                val b = rubymineIterator.next()\n                assert(a.name == b.name)\n                printWriter.println(\"Module: ${a.name}\")\n                var same = true\n                a.ancestors.filter { !b.ancestors.contains(it) }.let {\n                    if (!it.isEmpty()) {\n                        same = false\n                        printWriter.print(\"Ancestors in ObjectSpace only: \")\n                        it.forEach {\n                            val whereIncluded = ancestorHashSymbolIncluderToWhereIncluded[it + \"#\" + a.name]\n                            var toPrint = it\n                            if (whereIncluded != null) {\n                                toPrint += \"($whereIncluded)\"\n                            }\n                            printWriter.print(\"$toPrint \")\n                        }\n                        printWriter.println()\n                    }\n                }\n                b.ancestors.filter { !a.ancestors.contains(it) }.let {\n                    if (!it.isEmpty()) {\n                        same = false\n                        printWriter.print(\"Ancestors in RubyMine only: \")\n                        it.forEach { printWriter.print(\"$it \") }\n                        printWriter.println()\n                    }\n                }\n                if (same) {\n                    printWriter.println(\"No difference in ancestors list\")\n                }\n                printWriter.println()\n            }\n        }\n        moveProgressBarForward()\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/actions/ExportFileActionBase.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.actions\n\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.fileChooser.FileChooserDescriptor\nimport com.intellij.openapi.fileChooser.FileChooserDescriptorFactory\nimport com.intellij.openapi.fileChooser.FileSaverDescriptor\nimport com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl\nimport com.intellij.openapi.fileChooser.ex.FileSaverDialogImpl\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.progress.ProgressManager\nimport com.intellij.openapi.progress.util.ProgressWindow\nimport com.intellij.openapi.project.DumbAwareAction\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport com.intellij.openapi.ui.DialogBuilder\nimport com.intellij.openapi.ui.Messages\nimport com.intellij.openapi.util.ThrowableComputable\nimport org.jetbrains.plugins.ruby.ancestorsextractor.AncestorsExtractorBase\nimport org.jetbrains.plugins.ruby.ancestorsextractor.RailsConsoleRunner\nimport org.jetbrains.plugins.ruby.ruby.RModuleUtil\n\n/**\n * Base class representing file export action with \"save to\" dialog\n * @param whatToExport Will be shown in \"save to\" dialog\n * @param generateFilename Generate filename for \"save to\" dialog\n * @param extensions Array of available extensions for exported file\n * @param description Description in \"save to\" dialog\n */\nabstract class ExportFileActionBase(\n        private val whatToExport: String,\n        private val generateFilename: (Project) -> String,\n        private val extensions: Array<String>,\n        private val description: String = \"\",\n        private val numberOfProgressBarFractions: Int? = null\n) : DumbAwareAction() {\n    final override fun actionPerformed(e: AnActionEvent) {\n        val project = e.project ?: return\n        val dialog = FileSaverDialogImpl(FileSaverDescriptor(\n                \"Export $whatToExport\",\n                description,\n                *extensions), project)\n        val fileWrapper = dialog.save(null, generateFilename(project)) ?: return\n\n        val module: Module? = RModuleUtil.getInstance().getModule(e.dataContext)\n        val sdk: Sdk? = RModuleUtil.getInstance().findRubySdkForModule(module)\n\n        try {\n            ProgressManager.getInstance().runProcessWithProgressSynchronously(ThrowableComputable<Unit, Exception> {\n                return@ThrowableComputable backgroundProcess(fileWrapper.file.absolutePath, module, sdk, project)\n            }, \"Exporting $whatToExport\", false, project)\n        } catch (ex: Exception) {\n            Messages.showErrorDialog(ex.message, \"Error while exporting $whatToExport\")\n        }\n    }\n\n    /**\n     * In this method implementation you can do you job needed for file export and then file exporting itself.\n     *\n     * @param absoluteFilePath absolute file path which user have chosen to save file to.\n     * @param module module from the context of action it invoked\n     * @param sdk sdk from the context of action it invoked\n     * @param project project from the context of action it invoked\n     */\n    protected abstract fun backgroundProcess(absoluteFilePath: String, module: Module?, sdk: Sdk?, project: Project)\n\n    @Throws(IllegalStateException::class)\n    protected fun moveProgressBarForward() {\n        if (numberOfProgressBarFractions == null) throw IllegalStateException(\"You cannot call moveProgressBarForward() \" +\n                \"method when progressBarFractions property is null\")\n        val progressIndicator = ProgressManager.getInstance().progressIndicator\n        if (progressIndicator is ProgressWindow) {\n            progressIndicator.fraction = minOf(1.0, progressIndicator.fraction + 1.0/numberOfProgressBarFractions)\n        }\n    }\n\n    /**\n     * You can use to set as [AncestorsExtractorBase.listener] because every [ProgressListener]\n     * method call just calls [moveProgressBarForward]\n     */\n    protected inner class ProgressListener : RailsConsoleRunner.Listener {\n        override fun irbConsoleExecuted() {\n            moveProgressBarForward()\n        }\n\n        override fun informationWasExtractedFromIRB() {\n            moveProgressBarForward()\n        }\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/actions/ImportExportContractsAction.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.actions\n\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.fileChooser.FileChooserDescriptor\nimport com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.progress.ProgressIndicator\nimport com.intellij.openapi.progress.ProgressManager\nimport com.intellij.openapi.project.DumbAwareAction\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.projectRoots.Sdk\nimport com.intellij.openapi.ui.Messages\nimport com.intellij.openapi.util.ThrowableComputable\nimport org.jetbrains.exposed.sql.Database\nimport org.jetbrains.exposed.sql.selectAll\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.types.resetAllRubyTypeProviderAndIDEACaches\nimport org.jetbrains.ruby.codeInsight.types.signature.CallInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoRow\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\nimport java.io.File\n\nconst val CHUNK_SIZE = 1500\n\nfun Database.copyTo(destination: Database, moveProgressBar: Boolean) {\n    var progressIndicator: ProgressIndicator? = null\n    var count: Int? = null\n\n    if (moveProgressBar) {\n        progressIndicator = ProgressManager.getInstance().progressIndicator\n        count = transaction(this) { CallInfoTable.selectAll().count() }\n    }\n\n    var offset = 0\n    while (true) {\n        val info: List<CallInfo> = transaction(this) {\n            CallInfoRow.wrapRows(CallInfoTable.selectAll().limit(CHUNK_SIZE, offset)).map { it.copy() }\n        }\n        if (info.isEmpty()) {\n            break\n        }\n\n        transaction(destination) {\n            info.forEach { CallInfoTable.insertInfoIfNotContains(it) }\n        }\n\n        offset += CHUNK_SIZE\n\n        if (moveProgressBar) {\n            progressIndicator!!.fraction = offset.toDouble() / count!!\n        }\n    }\n}\n\nclass ExportContractsAction : ExportFileActionBase(\n        whatToExport = \"Type contracts\",\n        generateFilename = { project: Project -> \"${project.name}-type-contracts\" },\n        extensions = arrayOf(\"mv.db\")\n) {\n    override fun backgroundProcess(absoluteFilePath: String, module: Module?, sdk: Sdk?, project: Project) {\n        exportContractsToFile(absoluteFilePath, moveProgressBar = true)\n    }\n\n    companion object {\n        fun exportContractsToFile(pathToExport: String, moveProgressBar: Boolean) {\n            check(pathToExport.endsWith(DatabaseProvider.H2_DB_FILE_EXTENSION)) {\n                \"Path to export must end with .mv.db\"\n            }\n            File(pathToExport).delete()\n\n            val databaseToExportTo = DatabaseProvider.connectToDB(pathToExport)\n\n            DatabaseProvider.defaultDatabase!!.copyTo(databaseToExportTo, moveProgressBar)\n        }\n    }\n}\n\nclass ImportContractsAction : DumbAwareAction() {\n    override fun actionPerformed(e: AnActionEvent) {\n        val project = e.project\n        val files = FileChooserDialogImpl(\n                FileChooserDescriptor(true, false, false, false, false, false),\n                project).choose(project)\n\n        if (files.isEmpty()) {\n            return\n        }\n\n        try {\n            ProgressManager.getInstance().runProcessWithProgressSynchronously(ThrowableComputable<Unit, Exception> {\n                files.forEach { importContractsFromFile(it.path, moveProgressBar = true) }\n                return@ThrowableComputable\n            }, \"Importing type contracts\", false, project)\n            resetAllRubyTypeProviderAndIDEACaches(project)\n        } catch (ex: Exception) {\n            Messages.showErrorDialog(ex.message, \"Error while importing type contracts\")\n        }\n    }\n\n    companion object {\n        fun importContractsFromFile(pathToImportFrom: String, moveProgressBar: Boolean) {\n            check(pathToImportFrom.endsWith(DatabaseProvider.H2_DB_FILE_EXTENSION)) {\n                \"Path to import from must end with .mv.db\"\n            }\n\n            val dbToImportFrom = DatabaseProvider.connectToDB(pathToImportFrom)\n\n            dbToImportFrom.copyTo(DatabaseProvider.defaultDatabase!!, moveProgressBar)\n        }\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/ProjectLifecycleListenerImpl.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight\n\nimport com.google.gson.Gson\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.project.ProjectManagerListener\nimport org.jetbrains.plugins.ruby.ruby.persistent.TypeInferenceDirectory\nimport org.jetbrains.plugins.ruby.util.runServerAsyncInIDEACompatibleMode\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.runtime.signature.server.SignatureServer\nimport java.io.File\nimport java.io.PrintWriter\nimport java.nio.file.Paths\n\n/**\n * Short [Project] description for `rubymine-type-tracer`\n */\ndata class ProjectDescription(val projectName: String, val projectPath: String, val pipeFilePath: String) {\n    /**\n     * @param project default projects are not allowed!\n     */\n    constructor(project: Project, pipeFilePath: String) : this(project.name, project.basePath!!, pipeFilePath)\n}\n\n/**\n * This directory is needed for `rubymine-type-tracker` script\n *\n * In this directory we keep files named the same as currently opened projects in RubyMine.\n * Each file contains projectPath of pipe file required for arg-scanner.\n */\nprivate val openedProjectsDir = File(System.getProperty(\"java.io.tmpdir\")!!).resolve(\".ruby-type-inference\")\n        .also { it.mkdirs() }\n\n/**\n * This registered in `plugin.xml` and it's constructor called every time RubyMine starts\n */\nclass ProjectLifecycleListenerImpl : ProjectManagerListener {\n    private val gson = Gson()\n\n    private companion object {\n        @Volatile\n        private var initialized: Boolean = false\n    }\n\n    override fun projectOpened(project: Project) {\n        if (!project.isDefault) {\n            connectToDB(project.name)\n\n            // This server is used for `rubymine-type-tracker` script\n            startNewBackgroundInfinityServer(project)\n        }\n    }\n\n    override fun projectClosed(project: Project) {\n        if (!project.isDefault) {\n            val projectDescription = readProjectDescription(project, deleteJsonAfterRead = true)\n            File(projectDescription.pipeFilePath).delete()\n        }\n    }\n\n    private fun connectToDB(projectName: String) {\n        val filePath = Paths.get(\n                TypeInferenceDirectory.RUBY_TYPE_INFERENCE_DIRECTORY.toString(),\n                projectName).toString() + DatabaseProvider.H2_DB_FILE_EXTENSION\n\n        DatabaseProvider.connectToDB(filePath, isDefaultDatabase = true)\n    }\n\n    /**\n     * Starts server for `rubymine-type-tracker` script\n     */\n    private fun startNewBackgroundInfinityServer(project: Project): Boolean {\n        if (project.isDefault) {\n            return false\n        }\n\n        val server = SignatureServer()\n        val pipeFilePath: String = server.runServerAsyncInIDEACompatibleMode(project)\n\n        writeProjectDescription(ProjectDescription(project, pipeFilePath))\n\n        server.afterExitListener = {\n            startNewBackgroundInfinityServer(project)\n        }\n        return true\n    }\n\n    private fun writeProjectDescription(description: ProjectDescription) {\n        val jsonFile: File = openedProjectsDir.resolve(description.projectName)\n        PrintWriter(jsonFile).use { it.println(gson.toJson(description)) }\n    }\n\n    private fun readProjectDescription(project: Project, deleteJsonAfterRead: Boolean = false): ProjectDescription {\n        val jsonFile: File = openedProjectsDir.resolve(project.name)\n        val json: String = jsonFile.bufferedReader().use { it.readText() }\n        val description = gson.fromJson<ProjectDescription>(json, ProjectDescription::class.java)!!\n        if (deleteJsonAfterRead) {\n            jsonFile.delete()\n        }\n        return description\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/RubyDynamicCodeInsightPluginAppLifecyctlListener.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight\n\nimport com.intellij.ide.AppLifecycleListener\nimport com.intellij.openapi.project.Project\nimport org.jetbrains.plugins.ruby.RubyDynamicCodeInsightPluginInjector\nimport org.jetbrains.ruby.codeInsight.initInjector\n\nclass RubyDynamicCodeInsightPluginAppLifecyctlListener : AppLifecycleListener {\n    override fun appStarting(projectFromCommandLine: Project?) {\n        initInjector(RubyDynamicCodeInsightPluginInjector)\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/TrackerDataLoader.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight\n\nimport com.intellij.openapi.module.ModuleManager\nimport com.intellij.openapi.project.DumbAware\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.startup.StartupActivity\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker.RubyClassHierarchyWithCaching\n\nclass TrackerDataLoader : StartupActivity, DumbAware {\n    override fun runActivity(project: Project) {\n\n        ModuleManager.getInstance(project).modules.forEach {\n            RubyClassHierarchyWithCaching.loadFromSystemDirectory(it)\n        }\n\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/stateTracker/ClassHierarchySymbolProvider.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker\n\nimport com.intellij.openapi.module.ModuleUtilCore\nimport com.intellij.psi.PsiElement\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.RubySymbolProviderBase\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.fqn.FQN\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.Symbol\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.v2.SymbolPsiProcessor\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RPsiElement\n\nclass ClassHierarchySymbolProvider : RubySymbolProviderBase() {\n    override fun processDynamicSymbols(symbol: Symbol, element: RPsiElement?, fqn: FQN, processor: SymbolPsiProcessor,\n                                       invocationPoint: PsiElement?): Boolean {\n        if (element == null) {\n            return true\n        }\n\n        val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return true\n        val hierarchy = RubyClassHierarchyWithCaching.getInstance(module)?: return true\n        hierarchy.getMembersWithCaching(fqn.fullPath, symbol.rootSymbol).forEach {\n            if (!processor.process(it)) {\n                return false\n            }\n        }\n        return true\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/stateTracker/RubyClassHierarchyWithCaching.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker\n\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.util.Key\nimport com.intellij.util.containers.ContainerUtil\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.Type\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.Types\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.RMethodSyntheticSymbol\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.Symbol\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.SymbolUtil\nimport org.jetbrains.plugins.ruby.ruby.persistent.TypeInferenceDirectory\nimport org.jetbrains.plugins.ruby.settings.RubyTypeContractsSettings\nimport org.jetbrains.ruby.stateTracker.*\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.FileOutputStream\nimport java.util.zip.GZIPInputStream\nimport java.util.zip.GZIPOutputStream\n\nclass RubyClassHierarchyWithCaching private constructor(private val rubyClassHierachy: RubyClassHierarchy) {\n    private val lookupCache = ContainerUtil.createConcurrentWeakMap<Pair<String, String>, RubyMethod>()\n    private val membersCache = ContainerUtil.createConcurrentWeakMap<String, Set<Symbol>>()\n\n    fun getTypeForConstant(constant: String): RubyConstant? {\n        return rubyClassHierachy.topLevelConstants[constant]\n    }\n\n    fun getMembersWithCaching(moduleName: String, topLevel: Symbol) : Set<Symbol> {\n        val module = rubyClassHierachy.getRubyModule(moduleName) ?: return emptySet()\n        return getMembersWithCaching(module, topLevel)\n    }\n\n    private fun lookupInstanceMethodWithCaching(module: RubyModule, methodName: String) : RubyMethod? {\n        return lookupCache.computeIfAbsent(Pair(module.name, methodName)) { lookupInstanceMethod(module, methodName) }\n    }\n\n    private fun lookupInstanceMethod(module: RubyModule, methodName: String): RubyMethod? {\n        val ownResult = module.instanceMethods.firstOrNull {it.name == methodName}\n        if (ownResult != null) {\n            return ownResult\n        }\n\n        module.instanceDirectAncestors.forEach {\n            val result = lookupInstanceMethodWithCaching(it, methodName)\n            if (result != null) {\n                return result\n            }\n        }\n\n        if (module is RubyClass && module.superClass != RubyClass.EMPTY) {\n            val result = lookupInstanceMethodWithCaching(module.superClass, methodName)\n            if (result != null) {\n                return result\n            }\n        }\n\n        return null\n    }\n\n    private fun getMembersWithCaching(module: RubyModule, topLevel: Symbol) : Set<Symbol> {\n        return membersCache.computeIfAbsent(module.name) { getMembers(module, topLevel) }\n    }\n\n    private fun getMembers(module: RubyModule, topLevel: Symbol) : Set<Symbol> {\n        val set = HashSet<Symbol>()\n        val symbol = SymbolUtil.findSymbolInHierarchy(topLevel, module.name, Types.MODULE_OR_CLASS, topLevel.psiElement)\n        set.addAll(module.instanceMethods.map {  RMethodSyntheticSymbol(topLevel.project, Type.INSTANCE_METHOD, it, symbol) })\n        set.addAll(module.classMethods.map {  RMethodSyntheticSymbol(topLevel.project, Type.CLASS_METHOD, it, symbol) })\n\n        module.instanceDirectAncestors.forEach { set.addAll(getMembersWithCaching(it, topLevel))}\n        module.classDirectAncestors.forEach{ set.addAll(getMembersWithCaching(it, topLevel)) }\n\n        if (module is RubyClass && module.superClass != RubyClass.EMPTY) {\n            set.addAll(getMembersWithCaching(module.superClass, topLevel))\n        }\n\n        return set\n    }\n\n    companion object {\n        private val CLASS_HIERARCHY_KEY = Key<RubyClassHierarchyWithCaching>(\"org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker.ClassHierarchy\")\n\n        private val CLASS_HIERARCHY_FILENAME = \"-class-hierarchy.json.gz\"\n\n        fun loadFromSystemDirectory(module: Module): RubyClassHierarchyWithCaching? {\n            val file = File(TypeInferenceDirectory.RUBY_TYPE_INFERENCE_DIRECTORY.toFile(),\n                    module.project.name + \"-\" + module.name + CLASS_HIERARCHY_FILENAME)\n            if (!file.exists()) {\n                return null\n            }\n            FileInputStream(file).use {\n                GZIPInputStream(it).use {\n                    val json = it.reader(Charsets.UTF_8).use{ it.readText() }\n                    return createClassHierarchyFromJson(json, module)\n                }\n            }\n        }\n\n        @Synchronized\n        fun updateAndSaveToSystemDirectory(jsons: List<String>, module: Module) {\n            val json = RubyClassHierarchyLoader.mergeJsons(jsons)\n            createClassHierarchyFromJson(json, module)\n            FileOutputStream(File(TypeInferenceDirectory.RUBY_TYPE_INFERENCE_DIRECTORY.toFile(),\n                    module.project.name + \"-\" + module.name + CLASS_HIERARCHY_FILENAME)).use {\n                GZIPOutputStream(it).use {\n                    it.writer(Charsets.UTF_8).use { it.write(json) }\n                }\n            }\n        }\n\n        private fun createClassHierarchyFromJson(json: String, module: Module) : RubyClassHierarchyWithCaching {\n            val rubyClassHierarchy = RubyClassHierarchyWithCaching(RubyClassHierarchyLoader.fromJson(json))\n            module.putUserData(RubyClassHierarchyWithCaching.CLASS_HIERARCHY_KEY,\n                    rubyClassHierarchy)\n            return rubyClassHierarchy\n\n        }\n\n        fun getInstance(module: Module): RubyClassHierarchyWithCaching? {\n            if (!ServiceManager.getService(module.project, RubyTypeContractsSettings::class.java).stateTrackerEnabled) {\n                return null\n            }\n            val ret = module.getUserData(CLASS_HIERARCHY_KEY)\n            if (ret != null) {\n                return ret\n            }\n            return null\n        }\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/symbols/structure/RMethodSyntheticSymbol.java",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure;\n\nimport com.intellij.openapi.application.ReadAction;\nimport com.intellij.openapi.editor.Document;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.util.TextRange;\nimport com.intellij.openapi.vfs.VfsUtilCore;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.openapi.vfs.VirtualFileManager;\nimport com.intellij.psi.PsiDocumentManager;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.PsiManager;\nimport com.intellij.psi.util.CachedValueProvider;\nimport com.intellij.psi.util.CachedValuesManager;\nimport com.intellij.util.IncorrectOperationException;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.plugins.ruby.rdoc.yard.psi.RangeInDocumentFakePsiElement;\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.Type;\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.types.RType;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RPsiElement;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.controlStructures.methods.ArgumentInfo;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.controlStructures.methods.Visibility;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.impl.controlStructures.methods.RCommandArgumentListImpl;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.methodCall.RCall;\nimport org.jetbrains.ruby.stateTracker.Location;\nimport org.jetbrains.ruby.stateTracker.RubyMethod;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic class RMethodSyntheticSymbol extends SymbolImpl implements RMethodSymbol {\n    @NotNull\n    private final Visibility myVisibility;\n    @NotNull\n    private final List<ArgumentInfo> myArgsInfo;\n    @Nullable\n    private final String myPath;\n\n    private final int myLineno;\n\n    public RMethodSyntheticSymbol(@NotNull final Project project,\n                                  @NotNull final Type type,\n                                  @NotNull final RubyMethod rubyMethod,\n                                  @Nullable final Symbol parent) {\n        super(project, rubyMethod.getName(), type, parent);\n        myVisibility = Visibility.PUBLIC;\n        myArgsInfo = toArgsInfo(rubyMethod.getArguments());\n        final Location location = rubyMethod.getLocation();\n        if (location != null) {\n            myPath = location.getPath();\n            myLineno = location.getLineNo();\n        } else {\n            myPath = \"\";\n            myLineno = 0;\n        }\n    }\n\n    private List<ArgumentInfo> toArgsInfo(List<RubyMethod.ArgInfo> arguments) {\n        return arguments.stream().map(RMethodSyntheticSymbol::toArgumentInfo).collect(Collectors.toList());\n    }\n\n    private static ArgumentInfo toArgumentInfo(final @NotNull RubyMethod.ArgInfo argInfo) {\n        ArgumentInfo.Type type;\n        switch (argInfo.getKind()) {\n            case REQ:\n                type = ArgumentInfo.Type.SIMPLE;\n                break;\n            case OPT:\n                type = ArgumentInfo.Type.PREDEFINED;\n                break;\n            case REST:\n                type = ArgumentInfo.Type.ARRAY;\n                break;\n            case KEY:\n                type = ArgumentInfo.Type.NAMED;\n                break;\n            case KEY_REST:\n                type = ArgumentInfo.Type.HASH;\n                break;\n            case KEY_REQ:\n                type = ArgumentInfo.Type.KEYREQ;\n                break;\n            case BLOCK:\n                type = ArgumentInfo.Type.BLOCK;\n                break;\n            default:\n                throw new IllegalArgumentException(argInfo.getKind().toString());\n        }\n        return new ArgumentInfo(argInfo.getName(), type);\n    }\n\n    @NotNull\n    @Override\n    public String getName() {\n        //noinspection ConstantConditions\n        return super.getName();\n    }\n\n    @Override\n    public @Nullable\n    List<ArgumentInfo> getArgumentInfos() {\n        return myArgsInfo;\n    }\n\n    @Override\n    @Nullable\n    public List<ArgumentInfo> getArgumentInfos(boolean includeDefaultArgs) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public RType getCallType(@Nullable final RCall call) {\n        return null;\n    }\n\n    @NotNull\n    @Override\n    public String getArgsPresentation() {\n        if (myArgsInfo.isEmpty()) {\n            return \"\";\n        } else {\n            return \"(\" + RCommandArgumentListImpl.getPresentableName(myArgsInfo) + \")\";\n        }\n    }\n\n    @Override\n    public boolean isSynthetic() {\n        return false;\n    }\n\n    @NotNull\n    @Override\n    public Visibility getVisibility() {\n        return myVisibility;\n    }\n\n    @Override\n    public PsiElement getPsiElement() {\n        if (myPath == null) {\n            return null;\n        }\n        final VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(VfsUtilCore.pathToUrl(myPath));\n        if (virtualFile == null) {\n            return null;\n        }\n\n        final PsiFile file = PsiManager.getInstance(getProject()).findFile(virtualFile);\n        if (file == null) {\n            return null;\n        }\n\n        return CachedValuesManager.getCachedValue(file, () ->\n                CachedValueProvider.Result.create(calcElement(file), file));\n    }\n\n    @NotNull\n    @Override\n    public Collection<PsiElement> getAllDeclarations(PsiElement invocationPoint) {\n        final PsiElement psiElement = getPsiElement();\n        return psiElement == null ? Collections.emptyList() : Collections.singletonList(psiElement);\n    }\n\n    @Nullable\n    private PsiElement calcElement(@NotNull PsiFile file) {\n        final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file);\n        if (document == null) {\n            return null;\n        }\n        return ReadAction.compute(() -> {\n            int offset = document.getLineStartOffset(myLineno);\n            int nextLineOffset = document.getLineEndOffset(myLineno);\n            int curOffset = offset;\n            PsiElement psiElement;\n            do {\n                psiElement = file.findElementAt(curOffset);\n                if (psiElement == null) {\n                    return null;\n                }\n                curOffset = psiElement.getTextRange().getEndOffset();\n            } while (!(psiElement instanceof RPsiElement) && curOffset < nextLineOffset);\n\n            if (psiElement instanceof RPsiElement) {\n                return psiElement;\n            }\n\n            psiElement = file.findElementAt(offset);\n            if (psiElement == null) {\n                return null;\n            }\n            final int startElementOffset = psiElement.getTextRange().getStartOffset();\n            final int endElementOffset = psiElement.getTextRange().getEndOffset();\n            int start = offset - startElementOffset;\n            int end = Math.min(nextLineOffset - startElementOffset, endElementOffset - startElementOffset);\n            return new MyFakeElement(psiElement, new TextRange(start, end), getName());\n        });\n    }\n\n    private static class MyFakeElement extends RangeInDocumentFakePsiElement {\n        @NotNull\n        private final String myName;\n\n        MyFakeElement(@NotNull PsiElement parent, @NotNull TextRange rangeInParent, @NotNull String name) {\n            super(parent, rangeInParent);\n            myName = name;\n        }\n\n        @NotNull\n        @Override\n        public String getName() {\n            return myName;\n        }\n\n        @Override\n        public PsiElement setName(@NotNull String name) throws IncorrectOperationException {\n            throw new IncorrectOperationException(\"not supported\");\n        }\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/types/RubyCollectStateRunner.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.types\n\nimport com.intellij.execution.ExecutionException\nimport com.intellij.execution.configurations.RunProfile\nimport com.intellij.execution.configurations.RunProfileState\nimport com.intellij.execution.executors.CollectStateExecutor\nimport com.intellij.execution.runners.ExecutionEnvironment\nimport com.intellij.execution.ui.RunContentDescriptor\nimport com.intellij.openapi.util.io.FileUtil\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.AbstractRubyRunConfiguration\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.CollectExecSettings\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.RubyAbstractCommandLineState\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.RubyProgramRunner\nimport java.io.IOException\n\nclass RubyCollectStateRunner : RubyProgramRunner() {\n\n    override fun canRun(executorId: String, profile: RunProfile): Boolean {\n        return executorId == CollectStateExecutor.EXECUTOR_ID && profile is AbstractRubyRunConfiguration<*>\n    }\n\n    @Throws(ExecutionException::class)\n    override fun doExecute(state: RunProfileState,\n                           environment: ExecutionEnvironment): RunContentDescriptor? {\n        if (state is RubyAbstractCommandLineState) {\n            val newConfig = state.config.clone()\n            val pathToState =  tryGenerateTmpDirPath()\n\n            CollectExecSettings.putTo(newConfig,\n                    CollectExecSettings.createSettings(true,\n                            false,\n                            true,\n                            pathToState\n                    ))\n            val newState = newConfig.getState(environment.executor, environment)\n            if (newState != null) {\n                return super.doExecute(newState, environment)\n            }\n        }\n\n        return null\n    }\n\n\n    private fun tryGenerateTmpDirPath(): String? {\n        try {\n            val tmpDir = FileUtil.createTempDirectory(\"state-tracker\", \"\")\n            return tmpDir.absolutePath\n        } catch (ignored: IOException) {\n            return null\n        }\n\n    }\n\n    override fun getRunnerId(): String {\n        return RUBY_COLLECT_STATE_RUNNER_ID\n    }\n\n    companion object {\n        private val RUBY_COLLECT_STATE_RUNNER_ID = \"RubyCollectState\"\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/types/RubyRunWithTypeTrackerRunner.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.types\n\nimport com.intellij.execution.ExecutionException\nimport com.intellij.execution.configurations.RunProfile\nimport com.intellij.execution.configurations.RunProfileState\nimport com.intellij.execution.executors.RunWithTypeTrackerExecutor\nimport com.intellij.execution.runners.ExecutionEnvironment\nimport com.intellij.execution.ui.RunContentDescriptor\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.util.io.FileUtil\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.AbstractRubyRunConfiguration\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.CollectExecSettings\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.RubyAbstractCommandLineState\nimport org.jetbrains.plugins.ruby.ruby.run.configuration.RubyProgramRunner\nimport org.jetbrains.plugins.ruby.settings.RubyTypeContractsSettings\nimport java.io.IOException\n\nclass RubyRunWithTypeTrackerRunner : RubyProgramRunner() {\n\n    @Throws(ExecutionException::class)\n    override fun doExecute(state: RunProfileState,\n                           environment: ExecutionEnvironment): RunContentDescriptor? {\n        if (state is RubyAbstractCommandLineState) {\n            val (_, _, typeTrackerEnabled) = ServiceManager.getService(environment.project, RubyTypeContractsSettings::class.java)\n            val newConfig = state.config.clone()\n            val pathToState = tryGenerateTmpDirPath()\n\n            CollectExecSettings.putTo(newConfig,\n                    CollectExecSettings.createSettings(true,\n                            typeTrackerEnabled,\n                            false,\n                            pathToState\n                    ))\n            val newState = newConfig.getState(environment.executor, environment)\n            if (newState != null) {\n                return super.doExecute(newState, environment)\n            }\n        }\n\n        return null\n    }\n\n    override fun preloaderAllowed(): Boolean = false\n\n    private fun tryGenerateTmpDirPath(): String? = try {\n        val tmpDir = FileUtil.createTempDirectory(\"type-tracker\", \"\")\n        tmpDir.absolutePath\n    } catch (ignored: IOException) {\n        null\n    }\n\n    override fun canRun(executorId: String, profile: RunProfile): Boolean {\n        return executorId == RunWithTypeTrackerExecutor.EXECUTOR_ID && profile is AbstractRubyRunConfiguration<*>\n    }\n\n    override fun getRunnerId(): String {\n        return RUBY_COLLECT_TYPE_RUNNER_ID\n    }\n\n    companion object {\n        private val RUBY_COLLECT_TYPE_RUNNER_ID = \"RubyCollectType\"\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/codeInsight/types/RubyTypeProvider.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.codeInsight.types\n\nimport com.intellij.openapi.application.ReadAction\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.module.ModuleUtilCore\nimport com.intellij.openapi.progress.ProgressManager\nimport com.intellij.openapi.project.Project\nimport com.intellij.util.containers.ContainerUtil\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.AbstractRubyTypeProvider\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.IncomingType\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.resolve.ResolveUtil\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker.RubyClassHierarchyWithCaching\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.SymbolicExecutionContext\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.SymbolicExpressionProvider\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.SymbolicTypeInferenceProvider\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.TypeInferenceComponent\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.instance.TypeInferenceInstance\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.symbolicExpression.SymbolicCall\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbolicExecution.symbolicExpression.SymbolicExpression\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.Type\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.Symbol\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.util.SymbolHierarchy\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.types.impl.REmptyType\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RPsiElement\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RubyPsiUtil\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.expressions.RExpression\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.variables.RIdentifier\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport java.util.concurrent.Executors\nimport java.util.concurrent.Future\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.TimeoutException\n\n/**\n * Cache where we store last accessed [CallInfo]s. Thread safe\n */\nprivate val registeredCallInfosCache: MutableMap<MethodInfo, List<CallInfo>>\n        = ContainerUtil.createConcurrentSoftKeySoftValueMap<MethodInfo, List<CallInfo>>()\n\nfun resetAllRubyTypeProviderAndIDEACaches(project: Project?) {\n    registeredCallInfosCache.clear()\n    // Clears IDEAs caches about inferred types\n    ServiceManager.getService(project ?: return, TypeInferenceContext::class.java)?.clear()\n}\n\nfun getCachedOrComputedRegisteredCallInfo(methodInfo: MethodInfo): List<CallInfo> {\n    return registeredCallInfosCache.getOrPut(methodInfo) {\n        RSignatureProviderImpl.getRegisteredCallInfos(methodInfo)\n    }\n}\n\nclass RubyParameterTypeProvider : AbstractRubyTypeProvider() {\n    override fun createTypeBySymbol(symbol: Symbol): RType? {\n        return null\n    }\n\n    override fun createTypeByRExpression(expr: RExpression): RType? {\n        val symbol = ResolveUtil.resolveToSymbolWithCaching(expr.reference, false)\n        if (symbol?.type == Type.CONSTANT) {\n            val module = ModuleUtilCore.findModuleForPsiElement(expr) ?: return null\n            val classHierarchyWithCaching = RubyClassHierarchyWithCaching.getInstance(module) ?: return null\n            val path = symbol?.fqnWithNesting?.fullPath ?: return null\n            val constant = classHierarchyWithCaching.getTypeForConstant(path) ?: return null\n            val originType = RTypeFactory.createTypeByFQN(expr.project, constant.type)\n            val mixins = constant.extended.map { RTypeFactory.createTypeByFQN(expr.project, it) }\n            if (mixins.isNotEmpty()) {\n                return RTypeUtil.union(originType,  mixins.reduce { acc, it -> RTypeUtil.union(acc, it) })\n            }\n            return originType\n        }\n        if (expr is RIdentifier && expr.isParameter) {\n            val method = RubyPsiUtil.getContainingRMethod(expr) ?: return null\n            val rubyModuleName = RubyPsiUtil.getContainingRClassOrModule(method)?.fqn?.fullPath ?: \"Object\"\n\n            val info = MethodInfo.Impl(ClassInfo(rubyModuleName), method.fqn.shortName, RVisibility.PUBLIC)\n\n            val callInfos: List<CallInfo> = getCachedOrComputedRegisteredCallInfo(info)\n\n            val returnType = callInfos.map { callInfo ->\n                val typeName = expr.name?.let { callInfo.getTypeNameByArgumentName(it) } ?: return@map REmptyType.INSTANCE\n                return@map RTypeFactory.createTypeClassName(typeName, expr)\n            }.unionTypesSmart()\n            return if (returnType == REmptyType.INSTANCE) {\n                // If we don't have any information about type then return null\n                // in order to allow to RubyMine try to determine type itself\n                null\n            } else {\n                returnType\n            }\n        }\n        return null\n    }\n}\n\n/**\n * Provides types for Ruby method return values. Type providing based on information collection into [CallInfoTable]\n */\nclass ReturnTypeSymbolicTypeInferenceProvider : SymbolicTypeInferenceProvider {\n    companion object {\n        private val pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1)\n    }\n\n    override fun evaluateSymbolicCall(symbolicCall: SymbolicCall,\n                                      context: SymbolicExecutionContext,\n                                      callContext: TypeInferenceInstance.CallContext,\n                                      provider: SymbolicExpressionProvider,\n                                      component: TypeInferenceComponent): SymbolicExpression? {\n        ProgressManager.checkCanceled()\n        val job: () -> SymbolicExpression? = {\n            evaluateSymbolicCallPoolJob(symbolicCall, context, callContext, component)\n        }\n\n        val future: Future<SymbolicExpression?> = pool.submit(job)\n        return try {\n            // This method is run under read action and we cannot afford to spend a lot of time determining time.\n            // Otherwise we got glitches see: https://youtrack.jetbrains.com/issue/RUBY-25433\n            future.get(100, TimeUnit.MILLISECONDS)\n        } catch (ex: TimeoutException) {\n            null\n        }\n    }\n\n    private fun evaluateSymbolicCallPoolJob(symbolicCall: SymbolicCall,\n                                            context: SymbolicExecutionContext,\n                                            callContext: TypeInferenceInstance.CallContext,\n                                            component: TypeInferenceComponent): SymbolicExpression? {\n        var unnamedArgsTypes: List<String?> = emptyList()\n        var namedArgsTypes: List<ArgumentNameAndType?> = emptyList()\n        var receiverTypesConsideringAncestors: List<String> = emptyList()\n        ReadAction.run<Exception> {\n            ProgressManager.checkCanceled()\n            val exactReceiverType: RType = SymbolicTypeInferenceProvider.getReceiverType(symbolicCall, component, callContext)\n\n            // reversed because getAncestorsCaching gives us list of ancestors ordered from parent to end children\n            // This list already include exactReceiverType\n            receiverTypesConsideringAncestors = RTypeUtil.getBirthTypeSymbol(exactReceiverType)\n                    ?.let { SymbolHierarchy.getAncestorsCaching(it, callContext.invocationPoint) }\n                    ?.map { it.symbol.fqnWithNesting.toString() }?.reversed() ?: emptyList()\n\n            val typeInferenceComponent = context.getComponent(TypeInferenceComponent::class.java)\n\n            unnamedArgsTypes = symbolicCall.arguments.asSequence().filter { it.type != IncomingType.ASSOC }\n                    .map { typeInferenceComponent.getTypeForSymbolicExpression(it.expression).name }.toList()\n\n            namedArgsTypes = symbolicCall.arguments.asSequence().filter { it.type == IncomingType.ASSOC }\n                    .map {\n                        val type = typeInferenceComponent.getTypeForSymbolicExpression(it.expression).name ?: return@map null\n                        return@map ArgumentNameAndType(it.keyName, type)\n                    }.toList()\n        }\n\n        for (receiverTypeName in receiverTypesConsideringAncestors) {\n            val methodInfo = MethodInfo.Impl(ClassInfo.Impl(null, receiverTypeName), symbolicCall.name)\n\n            val registeredCallInfos = getCachedOrComputedRegisteredCallInfo(methodInfo)\n\n            val registeredReturnTypes: List<String> = registeredCallInfos\n                    .asSequence()\n                    .filter { argumentsMatch(it, unnamedArgsTypes, namedArgsTypes) }\n                    .map { it.returnType }\n                    .toList()\n                    .takeIf { !it.isEmpty() }\n                    ?: registeredCallInfos.map { it.returnType }\n\n            val returnType = registeredReturnTypes\n                    .mapNotNull {\n                        RTypeFactory.createTypeClassName(it, callContext.invocationPoint as? RPsiElement\n                                ?: return@mapNotNull null)\n                    }\n                    .unionTypesSmart()\n\n            if (returnType != REmptyType.INSTANCE) {\n                component.updateSymbolicExpressionType(symbolicCall, returnType)\n                return symbolicCall\n            }\n        }\n        // If we don't have any information about type then return null\n        // in order to allow to RubyMine try to determine type itself\n        return null\n    }\n\n    private fun argumentsMatch(oneOfExpected: CallInfo, actualUnnamedArgs: List<String?>, actualNamedArgs: List<ArgumentNameAndType?>): Boolean {\n        if (oneOfExpected.unnamedArguments.size != actualUnnamedArgs.size || oneOfExpected.namedArguments.size != actualNamedArgs.size) {\n            return false\n        }\n\n        if (oneOfExpected.unnamedArguments.zip(actualUnnamedArgs).any {\n                    it.first.type != ArgumentNameAndType.IMPLICITLY_PASSED_ARGUMENT_TYPE &&\n                            it.second != null &&\n                            it.first.type != it.second\n                }) {\n            return false\n        }\n\n        if (oneOfExpected.namedArguments.zip(actualNamedArgs).any {\n                    it.second != null &&\n                            it.first.type != ArgumentNameAndType.IMPLICITLY_PASSED_ARGUMENT_TYPE &&\n                            it.second!!.type != ArgumentNameAndType.IMPLICITLY_PASSED_ARGUMENT_TYPE &&\n                            it.first.type != it.second!!.type\n                }) {\n            return false\n        }\n\n        return true\n    }\n}\n\n/**\n * The same as [unionTypes] but also get rid of [REmptyType] and duplicates\n */\nprivate fun List<RType>.unionTypesSmart(): RType = filter { it != REmptyType.INSTANCE }.distinct().unionTypes()\n\nprivate fun List<RType>.unionTypes(): RType {\n    if (size == 0) {\n        return REmptyType.INSTANCE\n    }\n\n    if (size == 1) {\n        return first()\n    }\n    val m = size / 2\n    return RTypeUtil.union(subList(0, m).unionTypes(), subList(m, size).unionTypes())\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/intentions/AddContractAnnotationIntention.java",
    "content": "package org.jetbrains.plugins.ruby.ruby.intentions;\n\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.module.Module;\nimport com.intellij.openapi.module.ModuleUtilCore;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.util.text.StringUtil;\nimport com.intellij.psi.PsiDocumentManager;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.intellij.util.IncorrectOperationException;\nimport org.jetbrains.annotations.Nls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.exposed.dao.EntityID;\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.fqn.FQN;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RFile;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RubyElementFactory;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RubyPsiUtil;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.controlStructures.methods.RMethod;\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.variables.RFName;\nimport org.jetbrains.ruby.codeInsight.types.signature.*;\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ContractTransition;\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ReferenceContractTransition;\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.TypedContractTransition;\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider;\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.MethodInfoTable;\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class AddContractAnnotationIntention extends BaseRubyMethodIntentionAction {\n    @Nls(capitalization = Nls.Capitalization.Sentence)\n    @NotNull\n    @Override\n    public String getFamilyName() {\n        return getText();\n    }\n\n    public boolean isAvailable(@NotNull final Project project, final @NotNull Editor editor, @NotNull final PsiFile file) {\n        if (!super.isAvailable(project, editor, file)) {\n            return false;\n        }\n        if (!file.isWritable()) {\n            return false;\n        }\n        RFName rfName = getRFName(editor, file);\n        if (rfName == null) {\n            return false;\n        }\n        RMethod method = RubyPsiUtil.getContainingRMethod(rfName);\n        if (method == null) {\n            return false;\n        }\n\n        MethodInfo methodInfo = createMethodInfo(method);\n\n        EntityID<Integer> found = methodInfo != null ? DatabaseProvider.defaultDatabaseTransaction(\n                transaction -> MethodInfoTable.INSTANCE.findRowId(methodInfo)) : null;\n        return found != null;\n    }\n\n    public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {\n        PsiDocumentManager.getInstance(project).commitAllDocuments();\n        final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());\n        final RMethod method = PsiTreeUtil.getParentOfType(element, RMethod.class);\n        assert method != null : \"Method cannot be null here\";\n        final MethodInfo methodInfo = createMethodInfo(method);\n        assert methodInfo != null : \"MethodInfo mustn't be null: it was checked in isAvailable\";\n\n        List<CallInfo> registeredCallInfos = RSignatureProviderImpl.INSTANCE.getRegisteredCallInfos(methodInfo);\n\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"# @contract\");\n        for (CallInfo callInfo : registeredCallInfos) {\n            builder.append(\"\\n# (\");\n            builder.append(String.join(\", \", callInfo.getNamedArguments().stream().map(ArgumentNameAndType::getType).toArray(String[]::new)));\n            builder.append(\") -> \");\n            builder.append(callInfo.getReturnType());\n        }\n\n        final RFile fileWithComments = RubyElementFactory.createRubyFile(project, builder.toString());\n        method.getParent().addRangeBefore(fileWithComments.getFirstChild(), fileWithComments.getLastChild(), method);\n    }\n\n    @Nullable\n    private static MethodInfo createMethodInfo(@NotNull RMethod method) {\n        final FQN fqnWithNesting = method.getFQNWithNesting();\n        final String methodName = fqnWithNesting.getShortName();\n        final String receiverName = fqnWithNesting.getCallerFQN().getFullPath();\n        final Module module = ModuleUtilCore.findModuleForPsiElement(method);\n        if (module == null) {\n            return null;\n        }\n        return new MethodInfo.Impl(new ClassInfo.Impl(null, receiverName), methodName, RVisibility.PUBLIC, null);\n    }\n\n    private void dfs(@NotNull SignatureNode v, @NotNull StringBuilder currentLine, @NotNull List<String> result) {\n        if (result.size() > 3) {\n            return;\n        }\n        if (v.getTransitions().isEmpty()) {\n            result.add(currentLine.toString());\n            return;\n        }\n        if (v.getTransitions().size() == 1) {\n            v.getTransitions().forEach((edge, node) -> dfs(node, addEdge(currentLine, edgeToStr(edge)), result));\n            return;\n        }\n        Map<SignatureNode, List<String>> transitions = new HashMap<>();\n        v.getTransitions().forEach((edge, node) -> transitions.computeIfAbsent(node, (a) -> new ArrayList<>()).add(edgeToStr(edge)));\n        transitions.forEach((node, types) -> dfs(node, addEdge(new StringBuilder(currentLine), StringUtil.join(types, \" | \")), result));\n    }\n\n    private StringBuilder addEdge(@NotNull StringBuilder currentLine, String types) {\n        return currentLine.append(currentLine.length() == 0 ? \"\" : \", \").append(types);\n    }\n\n    private String edgeToStr(ContractTransition edge) {\n        if (edge instanceof ReferenceContractTransition) {\n            return \"T\" + (((ReferenceContractTransition) edge).getMask() + 1);\n        } else {\n            return ((TypedContractTransition) edge).getType();\n        }\n    }\n\n    @NotNull\n    @Override\n    protected String getTextByRubyFunctionNamePsiElement(@Nullable RFName element) {\n        return \"Add type contract\";\n    }\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/intentions/BaseRubyMethodIntentionAction.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.intentions\n\nimport com.intellij.codeInsight.intention.impl.BaseIntentionAction\nimport com.intellij.openapi.editor.Editor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.util.PsiTreeUtil\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.variables.RFName\n\nabstract class BaseRubyMethodIntentionAction : BaseIntentionAction() {\n    private var _text: String? = null\n\n    final override fun getText(): String = _text ?: getTextByRubyFunctionNamePsiElement(null)\n\n    protected abstract fun getTextByRubyFunctionNamePsiElement(element: RFName?): String\n\n    protected fun getRFName(editor: Editor, file: PsiFile): RFName? {\n        val offset = editor.caretModel.offset\n        val element = file.findElementAt(offset)\n        return PsiTreeUtil.getParentOfType(element, RFName::class.java)\n    }\n\n    override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {\n        val methodNameElement: RFName = getRFName(editor, file) ?: return false\n        _text = getTextByRubyFunctionNamePsiElement(methodNameElement)\n        return true\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/intentions/RemoveCollectedInfoIntention.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.intentions\n\nimport com.intellij.openapi.editor.Editor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiFile\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.types.resetAllRubyTypeProviderAndIDEACaches\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.RubyPsiUtil\nimport org.jetbrains.plugins.ruby.ruby.lang.psi.variables.RFName\nimport org.jetbrains.ruby.codeInsight.types.signature.ClassInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.MethodInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\n\nclass RemoveCollectedInfoIntention : BaseRubyMethodIntentionAction() {\n    override fun getFamilyName(): String = getText()\n\n    override fun getTextByRubyFunctionNamePsiElement(element: RFName?): String {\n        return \"Remove collected info about ${element?.name ?: \"this\"} method\"\n    }\n\n    override fun invoke(project: Project, editor: Editor, file: PsiFile) {\n        val method = getRFName(editor, file)?.let { RubyPsiUtil.getContainingRMethod(it) } ?: return\n        val rubyModuleName = RubyPsiUtil.getContainingRClassOrModule(method)?.fqn?.fullPath ?: \"Object\"\n\n        val info = MethodInfo.Impl(ClassInfo.Impl(null, rubyModuleName), method.fqn.shortName)\n\n        DatabaseProvider.defaultDatabaseTransaction { CallInfoTable.deleteAllInfoRelatedTo(info) }\n\n        resetAllRubyTypeProviderAndIDEACaches(project)\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/persistent/TypeInferenceDirectory.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.persistent\n\nimport com.intellij.openapi.application.PathManager\nimport com.intellij.openapi.util.io.FileUtil\nimport java.nio.file.Paths\n\nobject TypeInferenceDirectory {\n    val RUBY_TYPE_INFERENCE_DIRECTORY by lazy {\n        val path = Paths.get(PathManager.getSystemPath(), \"ruby-type-inference\")!!\n        FileUtil.createDirectory(path.toFile())\n        path\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/run/configuration/CollectExecSettings.java",
    "content": "package org.jetbrains.plugins.ruby.ruby.run.configuration;\n\nimport com.intellij.openapi.util.Key;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\npublic class CollectExecSettings {\n\n    @NotNull\n    private static final Key<CollectExecSettings> COLLECT_TYPE_EXEC_SETTINGS = new Key<>(\"CollectTypeExecSettings\");\n\n    private boolean myArgScannerEnabled;\n    private boolean myTypeTrackerEnabled;\n    private boolean myStateTrackerEnabled;\n    @Nullable\n    private String myOutputDirectory;\n\n    public boolean isArgScannerEnabled() {\n        return myArgScannerEnabled;\n    }\n\n    public boolean isStateTrackerEnabled() {\n        return myStateTrackerEnabled;\n    }\n\n    public void setStateTrackerEnabled(boolean myStateTrackerEnabled) {\n        this.myStateTrackerEnabled = myStateTrackerEnabled;\n    }\n\n    public void setArgScannerEnabled(boolean myArgScannerEnabled) {\n        this.myArgScannerEnabled = myArgScannerEnabled;\n    }\n\n    public boolean isTypeTrackerEnabled() {\n        return myTypeTrackerEnabled;\n    }\n\n    public void setTypeTrackerEnabled(boolean myTypeTrackerEnabled) {\n        this.myTypeTrackerEnabled = myTypeTrackerEnabled;\n    }\n\n    @Nullable\n    public String getOutputDirectory() {\n        return myOutputDirectory;\n    }\n\n    public void setReturnTypeTrackerPath(final @Nullable String path) {\n        myOutputDirectory = path;\n    }\n\n    @NotNull\n    public static CollectExecSettings getFrom(@NotNull final AbstractRubyRunConfiguration configuration) {\n        final CollectExecSettings data = configuration.getCopyableUserData(COLLECT_TYPE_EXEC_SETTINGS);\n        return data != null ? data : createSettings(false, false, false, null);\n    }\n\n    public static void putTo(@NotNull final AbstractRubyRunConfiguration configuration,\n                             @NotNull final CollectExecSettings settings) {\n        configuration.putCopyableUserData(COLLECT_TYPE_EXEC_SETTINGS, settings);\n    }\n\n    public static CollectExecSettings createSettings(final boolean argScannerEnabled,\n                                                         final boolean typeTrackerEnabled,\n                                                         final boolean stateTrackerEnabled,\n                                                         final String tempDirectoryPath\n    ) {\n        final CollectExecSettings settings = new CollectExecSettings();\n        settings.setArgScannerEnabled(argScannerEnabled);\n        settings.setTypeTrackerEnabled(typeTrackerEnabled);\n        settings.setReturnTypeTrackerPath(tempDirectoryPath);\n        settings.setStateTrackerEnabled(stateTrackerEnabled);\n\n        return settings;\n    }\n\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/ruby/run/configuration/RunWithTypeTrackerRunConfigurationExtension.java",
    "content": "package org.jetbrains.plugins.ruby.ruby.run.configuration;\n\nimport com.intellij.execution.configurations.GeneralCommandLine;\nimport com.intellij.execution.configurations.RunnerSettings;\nimport com.intellij.execution.process.ProcessAdapter;\nimport com.intellij.execution.process.ProcessEvent;\nimport com.intellij.execution.process.ProcessHandler;\nimport com.intellij.openapi.Disposable;\nimport com.intellij.openapi.diagnostic.Logger;\nimport com.intellij.openapi.module.Module;\nimport com.intellij.openapi.projectRoots.Sdk;\nimport com.intellij.openapi.ui.Messages;\nimport com.intellij.openapi.util.InvalidDataException;\nimport com.intellij.openapi.util.io.FileUtil;\nimport com.intellij.openapi.util.text.StringUtil;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.util.Alarm;\nimport com.intellij.util.AlarmFactory;\nimport org.jdom.Element;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.annotations.SystemIndependent;\nimport org.jetbrains.plugins.ruby.gem.GemDependency;\nimport org.jetbrains.plugins.ruby.gem.GemInfo;\nimport org.jetbrains.plugins.ruby.gem.GemInstallUtil;\nimport org.jetbrains.plugins.ruby.gem.util.GemSearchUtil;\nimport org.jetbrains.plugins.ruby.ruby.RubyUtil;\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.stateTracker.RubyClassHierarchyWithCaching;\nimport org.jetbrains.plugins.ruby.util.SignatureServerUtilKt;\nimport org.jetbrains.ruby.runtime.signature.server.SignatureServer;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\npublic class RunWithTypeTrackerRunConfigurationExtension extends RubyRunConfigurationExtension {\n    private static final Logger LOG = Logger.getInstance(RunWithTypeTrackerRunConfigurationExtension.class);\n    private static final String ARG_SCANNER_GEM_NAME = \"arg_scanner\";\n\n    private static final String ARG_SCANNER_REQUIRE_SCRIPT = \"arg_scanner/starter\";\n\n    private static final String ENABLE_TYPE_TRACKER_KEY = \"ARG_SCANNER_ENABLE_TYPE_TRACKER\";\n\n    private static final String ENABLE_STATE_TRACKER_KEY = \"ARG_SCANNER_ENABLE_STATE_TRACKER\";\n\n    private static final String PROJECT_ROOT_KEY = \"ARG_SCANNER_PROJECT_ROOT\";\n\n    private static final String ARG_SCANNER_PIPE_FILE_PATH_KEY = \"ARG_SCANNER_PIPE_FILE_PATH\";\n\n    private static final String OUTPUT_DIRECTORY = \"ARG_SCANNER_DIR\";\n\n    private static final int MAX_RETRY_NO = 15;\n\n    private static final int RETRY_TIMEOUT = 2000;\n\n\n    @Override\n    protected void readExternal(@NotNull final AbstractRubyRunConfiguration runConfiguration,\n                                @NotNull final Element element) throws InvalidDataException {\n\n    }\n\n    @Nullable\n    @Override\n    protected String getEditorTitle() {\n        return null;\n    }\n\n    @Override\n    public boolean isApplicableFor(@NotNull AbstractRubyRunConfiguration<?> configuration) {\n        return true;\n    }\n\n    @Override\n    public boolean isEnabledFor(@NotNull AbstractRubyRunConfiguration<?> applicableConfiguration,\n                                @Nullable RunnerSettings runnerSettings) {\n        final CollectExecSettings config = CollectExecSettings.getFrom(applicableConfiguration);\n        return config.isArgScannerEnabled();\n    }\n\n    @Override\n    protected void patchCommandLine(@NotNull final AbstractRubyRunConfiguration configuration,\n                                    @Nullable final RunnerSettings runnerSettings,\n                                    @NotNull final GeneralCommandLine cmdLine,\n                                    @NotNull final String runnerId) {\n        final Module module = configuration.getModule();\n        if (module == null) {\n            return;\n        }\n\n        String includeKey = getRequireKeyForGem(module, configuration.getSdk(), ARG_SCANNER_GEM_NAME);\n        if (includeKey == null) {\n            return;\n        }\n\n        String pipeFileName = SignatureServerUtilKt.runServerAsyncInIDEACompatibleMode(new SignatureServer(), configuration.getProject());\n\n        final Map<String, String> env = cmdLine.getEnvironment();\n        final String rubyOpt = StringUtil.notNullize(env.get(RubyUtil.RUBYOPT));\n        final CollectExecSettings collectTypeSettings = CollectExecSettings.getFrom(configuration);\n        if (collectTypeSettings.isTypeTrackerEnabled()) {\n            env.put(ENABLE_TYPE_TRACKER_KEY, \"1\");\n        }\n        if (collectTypeSettings.isStateTrackerEnabled()) {\n            env.put(ENABLE_STATE_TRACKER_KEY, \"1\");\n        }\n        if (collectTypeSettings.getOutputDirectory() != null) {\n            env.put(OUTPUT_DIRECTORY, collectTypeSettings.getOutputDirectory());\n        }\n        @SystemIndependent String basePath = configuration.getProject().getBasePath();\n        if (basePath != null) {\n            env.put(PROJECT_ROOT_KEY, basePath);\n        }\n        env.put(ARG_SCANNER_PIPE_FILE_PATH_KEY, pipeFileName);\n\n        final String newRubyOpt = rubyOpt + includeKey + \" -r\" + ARG_SCANNER_REQUIRE_SCRIPT;\n\n        cmdLine.withEnvironment(RubyUtil.RUBYOPT, newRubyOpt);\n    }\n\n    @Override\n    protected void validateConfiguration(@NotNull AbstractRubyRunConfiguration configuration, boolean isExecution) throws Exception {\n        RunConfigurationUtil.inspectSDK(configuration, isExecution);\n        final Module module = configuration.getModule();\n        final Sdk sdk = configuration.getSdk();\n        if (module == null || sdk == null) {\n            RunConfigurationUtil.throwExecutionOrRuntimeException(\"Cannot execute outside of module context\", isExecution);\n        }\n\n        GemInfo argScannerGem = GemSearchUtil.findGem(module, sdk, ARG_SCANNER_GEM_NAME);\n        if (argScannerGem == null) {\n            if (isExecution) {\n                final int result = Messages.showYesNoDialog(configuration.getProject(),\n                        \"'arg_scanner' gem is required to collect the data. Do you want to install it?\",\n                        \"Gem Not Found\", null);\n                if (result == Messages.YES) {\n                    final HashMap<GemDependency, String> errors = new HashMap<>();\n                    GemInstallUtil.installGemsDependencies(sdk,\n                            module,\n                            Collections.singleton(GemDependency.create(ARG_SCANNER_GEM_NAME, \">= 0.3.3\")),\n                            true,\n                            false,\n                            errors);\n                    if (errors.isEmpty()) {\n                        // means success\n                        return;\n                    }\n                }\n            }\n\n            RunConfigurationUtil.throwExecutionOrRuntimeException(\"Cannot find required \" + ARG_SCANNER_GEM_NAME +\n                    \" gem in the current SDK\", false);\n        }\n    }\n\n    @Nullable\n    private String getRequireKeyForGem(@NotNull Module module, @Nullable Sdk sdk, @NotNull String gemName) {\n        final GemInfo gemInfo = GemSearchUtil.findGem(module, sdk, gemName);\n        if (gemInfo == null) {\n            return null;\n        }\n\n        final VirtualFile libFolder = gemInfo.getLibFolder();\n        if (libFolder == null) {\n            return null;\n        }\n        return \" -I\" + libFolder.getPath();\n    }\n\n    @Override\n    protected void attachToProcess(@NotNull AbstractRubyRunConfiguration configuration,\n                                   @NotNull ProcessHandler handler, @Nullable RunnerSettings runnerSettings) {\n        final CollectExecSettings settings = CollectExecSettings.getFrom(configuration);\n        if (settings.isStateTrackerEnabled()) {\n            handler.addProcessListener(\n                new ProcessAdapter() {\n                    @Override\n                    public void processTerminated(@NotNull ProcessEvent event) {\n                        processStateTrackerResult(settings, configuration);\n                    }\n                }\n            );\n        }\n    }\n\n    private boolean checkForPidFiles(final @NotNull File directory) {\n        File[] listOfFiles = directory.listFiles();\n        return listOfFiles != null && Arrays.stream(listOfFiles).anyMatch((it) -> it.getName().endsWith(\".pid\"));\n    }\n\n    private void waitAllProcess(final @NotNull File directory,\n                                final @NotNull Runnable task,\n                                final @NotNull Disposable parent,\n                                int tryNo) {\n        if (!checkForPidFiles(directory) || tryNo > MAX_RETRY_NO) {\n            task.run();\n        } else {\n            AlarmFactory.getInstance().create(Alarm.ThreadToUse.POOLED_THREAD, parent).addRequest(\n                    () -> waitAllProcess(directory, task, parent,tryNo + 1), RETRY_TIMEOUT);\n        }\n    }\n\n    private void processStateTrackerResult(final @NotNull CollectExecSettings settings,\n                                           final @NotNull AbstractRubyRunConfiguration configuration) {\n        String directoryPath = settings.getOutputDirectory();\n        assert directoryPath != null;\n        File directory = new File(directoryPath);\n        final Module module = configuration.getModule();\n        if (module == null) {\n            return;\n        }\n        waitAllProcess(directory, () -> {\n            try {\n                File[] listOfFiles = directory.listFiles();\n                if (listOfFiles == null) {\n                    return;\n                }\n\n                final List<String> jsons = Arrays.stream(listOfFiles).filter((it) -> it.getName().endsWith(\"json\")).map((it) -> {\n                    try {\n                        return FileUtil.loadFile(it);\n                    } catch (IOException e) {\n                        LOG.warn(e);\n                        return null;\n                    }\n                }).filter(Objects::nonNull).collect(Collectors.toList());\n                if (jsons.isEmpty()) {\n                    return;\n                }\n                if (settings.isStateTrackerEnabled()) {\n                    RubyClassHierarchyWithCaching.Companion.updateAndSaveToSystemDirectory(jsons, module);\n                }\n            } finally {\n                FileUtil.delete(directory);\n            }\n        },  module, 0);\n    }\n\n\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/settings/RubyTypeContractsConfigurable.kt",
    "content": "package org.jetbrains.plugins.ruby.settings\n\nimport com.intellij.openapi.options.ConfigurableBase\n\nclass RubyTypeContractsConfigurable(private val settings: RubyTypeContractsSettings) :\n        ConfigurableBase<RubyTypeContractsConfigurableUI,\n                         RubyTypeContractsSettings>(RubyTypeContractsConfigurable::class.java.name,\n                                                    \"Ruby Type Contracts\", null) {\n\n    override fun getSettings(): RubyTypeContractsSettings {\n        return settings\n    }\n\n    override fun createUi(): RubyTypeContractsConfigurableUI {\n        return RubyTypeContractsConfigurableUI(settings)\n    }\n\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/settings/RubyTypeContractsConfigurableUI.kt",
    "content": "package org.jetbrains.plugins.ruby.settings\n\nimport com.intellij.openapi.options.ConfigurableUi\nimport com.intellij.openapi.ui.VerticalFlowLayout\nimport com.intellij.ui.BooleanTableCellEditor\nimport com.intellij.ui.BooleanTableCellRenderer\nimport com.intellij.ui.ToolbarDecorator\nimport com.intellij.ui.components.JBPanel\nimport com.intellij.ui.table.TableView\nimport com.intellij.util.text.VersionComparatorUtil\nimport com.intellij.util.ui.CheckBox\nimport com.intellij.util.ui.ColumnInfo\nimport com.intellij.util.ui.JBUI\nimport com.intellij.util.ui.ListTableModel\nimport org.jetbrains.exposed.sql.and\nimport org.jetbrains.exposed.sql.deleteWhere\nimport org.jetbrains.ruby.codeInsight.types.signature.GemInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.GemInfoTable\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport java.util.*\nimport javax.swing.JComponent\nimport javax.swing.JTable\nimport javax.swing.ListSelectionModel\nimport kotlin.collections.ArrayList\nimport kotlin.collections.HashMap\n\nclass RubyTypeContractsConfigurableUI(settings: RubyTypeContractsSettings) : ConfigurableUi<RubyTypeContractsSettings> {\n    private val toBeRemovedGems = ArrayList<GemInfo>()\n\n    private val registeredGems = ArrayList(RSignatureProviderImpl.registeredGems)\n\n    private val perGemSettingsMap = HashMap(settings.perGemSettingsMap)\n\n    private var typeTrackerEnabled = settings.typeTrackerEnabled\n    private var stateTrackerEnabled = settings.stateTrackerEnabled\n\n    private val tableModel = ListTableModel<GemInfo>(\n            object : ColumnInfo<GemInfo, String>(\"Gem Name\") {\n                override fun valueOf(item: GemInfo?) = item?.name\n            },\n            object : ColumnInfo<GemInfo, String>(\"Version\") {\n                override fun valueOf(item: GemInfo?) = item?.version\n\n                override fun getComparator() = Comparator<GemInfo> { gemInfo1, gemInfo2 ->\n                    VersionComparatorUtil.COMPARATOR.compare(gemInfo1.version, gemInfo2.version)\n                }\n            },\n            object : ColumnInfo<GemInfo, Boolean>(\"Share\") {\n                private val renderer = BooleanTableCellRenderer()\n\n                private val editor = BooleanTableCellEditor()\n\n                private val width = Math.max(\n                        renderer.preferredSize.width,\n                        renderer.getFontMetrics(renderer.font).stringWidth(name) + 10)\n\n                override fun getWidth(table: JTable?): Int = width\n\n                override fun valueOf(item: GemInfo?) = perGemSettingsMap[item]?.share != false && item?.name != LOCAL_SOURCE_GEM_NAME\n\n                override fun isCellEditable(item: GemInfo?) = item?.name != LOCAL_SOURCE_GEM_NAME\n\n                override fun getRenderer(item: GemInfo?) = renderer\n\n                override fun getEditor(item: GemInfo?) = editor\n\n                override fun setValue(item: GemInfo, value: Boolean) {\n                    if (value) {\n                        perGemSettingsMap.remove(item)\n                    } else {\n                        perGemSettingsMap.put(GemInfoBean(item.name, item.version), PerGemSettings(false))\n                    }\n                }\n            }\n    )\n\n    private val tableView = TableView<GemInfo>(tableModel)\n\n    init {\n        tableView.intercellSpacing = JBUI.emptySize()\n        tableView.isStriped = true\n        tableView.cellSelectionEnabled = false\n        tableView.rowSelectionAllowed = true\n        tableView.showHorizontalLines = false\n        tableView.showVerticalLines = false\n        tableView.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)\n        refill()\n    }\n\n    override fun reset(settings: RubyTypeContractsSettings) {\n        perGemSettingsMap.clear()\n        perGemSettingsMap.putAll(settings.perGemSettingsMap)\n        typeTrackerEnabled = settings.typeTrackerEnabled\n        stateTrackerEnabled = settings.stateTrackerEnabled\n        toBeRemovedGems.clear()\n        refill()\n    }\n\n    override fun isModified(settings: RubyTypeContractsSettings): Boolean {\n        return perGemSettingsMap != settings.perGemSettingsMap || toBeRemovedGems.isNotEmpty()\n                || settings.stateTrackerEnabled != stateTrackerEnabled\n                || settings.typeTrackerEnabled != typeTrackerEnabled\n    }\n\n    override fun apply(settings: RubyTypeContractsSettings) {\n        if (toBeRemovedGems.isNotEmpty()) {\n            DatabaseProvider.defaultDatabaseTransaction {\n                toBeRemovedGems.forEach {\n                    GemInfoTable.deleteWhere { GemInfoTable.name eq it.name and (GemInfoTable.version eq it.version) }\n                }\n                perGemSettingsMap.keys.removeAll(toBeRemovedGems)\n                registeredGems.removeAll(toBeRemovedGems)\n            }\n        }\n        settings.stateTrackerEnabled = stateTrackerEnabled\n        settings.typeTrackerEnabled = typeTrackerEnabled\n        settings.perGemSettingsMap = HashMap(perGemSettingsMap)\n        refill()\n    }\n\n    override fun getComponent(): JComponent {\n        val panel = JBPanel<JBPanel<*>>(VerticalFlowLayout())\n        panel.add(ToolbarDecorator.createDecorator(tableView.component)\n                .setRemoveAction { _ ->\n                    val selectedObject = tableView.selectedObject\n                            ?: return@setRemoveAction\n                    val selectedRowNumber = tableView.selectedRow\n\n                    toBeRemovedGems.add(selectedObject)\n                    tableModel.removeRow(tableView.selectedRow)\n\n                    tableView.selectionModel.setSelectionInterval(-239, Math.min(selectedRowNumber, tableModel.rowCount - 1))\n                }\n                .disableAddAction()\n                .disableUpDownActions().createPanel())\n        panel.add(CheckBox(\"Use state tracker results for completion\", this, \"stateTrackerEnabled\"))\n        panel.add(CheckBox(\"Use type tracker results for completion\", this, \"typeTrackerEnabled\"))\n        return panel\n    }\n\n    private fun refill() {\n        tableModel.items = registeredGems.map { GemInfoBean(it.name, it.version) }\n    }\n\n    companion object {\n        private val LOCAL_SOURCE_GEM_NAME = \"LOCAL\"\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/settings/RubyTypeContractsSettings.kt",
    "content": "package org.jetbrains.plugins.ruby.settings\n\nimport com.intellij.openapi.components.PersistentStateComponent\nimport com.intellij.openapi.components.State\nimport com.intellij.openapi.components.Storage\nimport com.intellij.util.xmlb.XmlSerializerUtil\nimport com.intellij.util.xmlb.annotations.Attribute\nimport com.intellij.util.xmlb.annotations.MapAnnotation\nimport org.jetbrains.ruby.codeInsight.types.signature.GemInfo\n\n@State(\n        name = \"RubyTypeContractsSettings\",\n        storages = arrayOf(Storage(\"ruby_type_inference.xml\"))\n)\ndata class RubyTypeContractsSettings @JvmOverloads constructor(\n        @Attribute\n        var localSourcesTrackingPolicy: LocalSourcesTrackingPolicy = LocalSourcesTrackingPolicy.ACCUMULATE,\n        @MapAnnotation\n        var perGemSettingsMap: MutableMap<GemInfoBean, PerGemSettings> = HashMap(),\n        @Attribute(\"typeTrackerEnabled\")\n        var typeTrackerEnabled: Boolean = true,\n        @Attribute(\"stateTrackerEnabled\")\n        var stateTrackerEnabled: Boolean = true)\n\n    : PersistentStateComponent<RubyTypeContractsSettings> {\n    override fun loadState(state: RubyTypeContractsSettings) {\n        XmlSerializerUtil.copyBean(state, this)\n    }\n\n    override fun getState(): RubyTypeContractsSettings? = this\n}\n\nenum class LocalSourcesTrackingPolicy {\n    IGNORE,\n    CLEAR_ON_CHANGES,\n    ACCUMULATE\n}\n\ndata class GemInfoBean(@Attribute(\"name\") override val name: String = \"\",\n                       @Attribute(\"version\") override val version: String = \"\") : GemInfo\n\ndata class PerGemSettings(@Attribute(\"share\") val share: Boolean) {\n    @Suppress(\"unused\")\n    private constructor() : this(true)\n}"
  },
  {
    "path": "ide-plugin/src/org/jetbrains/plugins/ruby/util/SignatureServerUtil.kt",
    "content": "package org.jetbrains.plugins.ruby.util\n\nimport com.intellij.openapi.project.Project\nimport org.jetbrains.plugins.ruby.ruby.codeInsight.types.resetAllRubyTypeProviderAndIDEACaches\nimport org.jetbrains.ruby.runtime.signature.server.SignatureServer\n\n/**\n * Runs [SignatureServer] in IDEA compatible mode (for example IDEAs caches will be cleaned after server\n * flushes data to DB. Server is launched in daemon mode and so on)\n *\n * @return pipe filename path which should be passed to arg-scanner.\n */\nfun SignatureServer.runServerAsyncInIDEACompatibleMode(project: Project): String {\n    this.afterFlushListener = {\n        resetAllRubyTypeProviderAndIDEACaches(project)\n    }\n    return this.runServerAsync(isDaemon = true)\n}\n"
  },
  {
    "path": "ide-plugin/src/test/java/CallStatCompletionTest.kt",
    "content": "import com.intellij.execution.ExecutionException\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase\nimport junit.framework.Assert\nimport org.jetbrains.plugins.ruby.ruby.run.RubyCommandLine\nimport org.jetbrains.plugins.ruby.ruby.run.RubyLocalRunner\nimport org.jetbrains.ruby.codeInsight.types.signature.CallInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.ClassInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.MethodInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.RVisibility\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport org.jetbrains.ruby.runtime.signature.server.SignatureServer\nimport java.io.IOException\nimport java.util.concurrent.TimeUnit\n\nclass CallStatCompletionTest : LightPlatformCodeInsightFixtureTestCase() {\n\n    private var lastServer: SignatureServer? = null\n\n    override fun getTestDataPath(): String {\n        return \"src/test/testData\"\n    }\n\n    override fun setUp() {\n        super.setUp()\n        DatabaseProvider.connectToInMemoryDB(isDefaultDatabase = true)\n        DatabaseProvider.dropAllDatabases()\n        DatabaseProvider.createAllDatabases()\n    }\n\n    override fun tearDown() {\n        try {\n            DatabaseProvider.dropAllDatabases()\n        } finally {\n            super.tearDown()\n        }\n    }\n\n    fun testSimpleCallInfoCollection() {\n        val callInfos = runAndGetCallInfos(\"simple_call_info_collection_test.rb\",\n                createMethodInfo(\"AClass\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"Symbol\")\n    }\n\n    fun testSimpleCallInfosCollectionMultipleFunctions() {\n        executeScript(\"simple_call_info_collection_test_multiple_functions_test.rb\")\n        waitForServer()\n\n        val fooCallInfos = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"A\", \"foo\"))\n        val barCallInfos = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"A\", \"bar\"))\n\n        assertEquals(1, fooCallInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(fooCallInfos, 2))\n        assertCallInfosContainsUnique(fooCallInfos, listOf(\"String\", \"Class\"), \"String\")\n\n        assertEquals(3, barCallInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(barCallInfos, 1))\n        assertCallInfosContainsUnique(barCallInfos, listOf(\"TrueClass\"), \"A\")\n        assertCallInfosContainsUnique(barCallInfos, listOf(\"FalseClass\"), \"FalseClass\")\n        assertCallInfosContainsUnique(barCallInfos, listOf(\"Symbol\"), \"A\")\n    }\n\n    fun testSimpleCallInfosCollectionWithMultipleArguments() {\n        val callInfos = runAndGetCallInfos(\"simple_call_info_collection_with_multiple_arguments_test.rb\",\n                createMethodInfo(\"AClass\", \"foo\"))\n\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 2))\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\", \"TrueClass\"), \"Regexp\")\n    }\n\n    fun testSaveTypesBetweenLaunches() {\n        var callInfos = runAndGetCallInfos(\"save_types_between_launches_test_part_1.rb\",\n                createMethodInfo(\"A\", \"foo\"))\n        assertEquals(2, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"Symbol\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"Class\"), \"A\")\n\n        callInfos = runAndGetCallInfos(\"save_types_between_launches_test_part_2.rb\",\n                createMethodInfo(\"A\", \"foo\"))\n        assertEquals(4, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"Symbol\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"Class\"), \"A\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"TrueClass\"), \"FalseClass\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"Regexp\")\n    }\n\n    fun testForgetCallInfoWhenArgumentsNumberChanged() {\n        var callInfos = runAndGetCallInfos(\"forget_call_info_when_arguments_number_changed_test_part_1.rb\",\n                createMethodInfo(\"A\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"Symbol\")\n\n        callInfos = runAndGetCallInfos(\"forget_call_info_when_arguments_number_changed_test_part_2.rb\",\n                createMethodInfo(\"A\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 2))\n        assertCallInfosContainsUnique(callInfos, listOf(\"TrueClass\", \"FalseClass\"), \"FalseClass\")\n    }\n\n    fun testCallInfoOfNestedClass() {\n        val callInfos = runAndGetCallInfos(\"call_info_of_nested_class_test.rb\",\n                createMethodInfo(\"M::A\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n        assertCallInfosContainsUnique(callInfos, listOf(\"M::A\"), \"M::A\")\n    }\n\n    fun testTopLevelMethodsCallInfoCollection() {\n        val callInfos = runAndGetCallInfos(\"top_level_methods_call_info_collection_test.rb\",\n                createMethodInfo(\"Object\", \"foo\"))\n        assertEquals(4, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 2))\n        assertCallInfosContainsUnique(callInfos, listOf(\"TrueClass\", \"FalseClass\"), \"TrueClass\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"FalseClass\", \"Symbol\"), \"Symbol\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\", \"TrueClass\"), \"Regexp\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\", \"TrueClass\"), \"String\")\n    }\n\n    fun testDuplicatesInCallInfoTable() {\n        val callInfos = runAndGetCallInfos(\"duplicates_in_callinfo_table_test.rb\",\n                createMethodInfo(\"Object\", \"foo\"))\n        assertEquals(3, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 1))\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"String\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\"), \"FalseClass\")\n        assertCallInfosContainsUnique(callInfos, listOf(\"FalseClass\"), \"FalseClass\")\n    }\n\n    fun testMethodWithoutParameters() {\n        val callInfos = runAndGetCallInfos(\"method_without_parameters_test.rb\",\n                createMethodInfo(\"Object\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 0))\n        assertCallInfosContainsUnique(callInfos, emptyList(), \"String\")\n    }\n\n    fun testAnonymousModuleMethodCall() {\n        val callInfos = runAndGetCallInfos(\"anonymous_module_method_call_test.rb\",\n                createMethodInfo(\"A\", \"foo\"))\n        assertEquals(1, callInfos.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(callInfos, 2))\n        assertCallInfosContainsUnique(callInfos, listOf(\"String\", \"Symbol\"), \"TrueClass\")\n    }\n\n    fun testRubyExecWithBuffering() {\n        executeScript(\"ruby_exec_test.rb\", additionalArgScannerArgs = arrayOf(\"--buffering\"))\n        waitForServer()\n        val foo: List<CallInfo> = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"foo\"))\n        val bar: List<CallInfo> = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"bar\"))\n\n        assertEquals(0, foo.size)\n\n        assertEquals(1, bar.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(bar, 1))\n        assertCallInfosContainsUnique(bar, listOf(\"TrueClass\"), \"NilClass\")\n    }\n\n    fun testRubyExecWithoutBuffering() {\n        executeScript(\"ruby_exec_test.rb\")\n        waitForServer()\n        val foo: List<CallInfo> = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"foo\"))\n        val bar: List<CallInfo> = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"bar\"))\n\n        assertEquals(1, foo.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(foo, 1))\n        assertCallInfosContainsUnique(foo, listOf(\"String\"), \"NilClass\")\n\n        assertEquals(1, bar.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(bar, 1))\n        assertCallInfosContainsUnique(bar, listOf(\"TrueClass\"), \"NilClass\")\n    }\n\n    fun testGemFunctionsCatchingWithProjectRootSpecified() {\n        val runnableScriptName = \"in_project_root_test/in_project_root_test.rb\"\n        val projectRoot: String = javaClass.classLoader.getResource(runnableScriptName).path\n        executeScript(runnableScriptName, additionalArgScannerArgs = arrayOf(\"--project-root=$projectRoot\"))\n        waitForServer()\n\n        val catch = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"catch\"))\n        assertEquals(1, catch.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(catch, 1))\n        assertCallInfosContainsUnique(catch, listOf(\"String\"), \"NilClass\")\n\n        val catch_2 = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"catch_2\"))\n        assertEquals(1, catch_2.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(catch_2, 1))\n        assertCallInfosContainsUnique(catch_2, listOf(\"String\"), \"NilClass\")\n\n        val dont_catch_2 = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"dont_catch_2\"))\n        assertEquals(0, dont_catch_2.size)\n\n        val catch_3 = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"catch_3\"))\n        assertEquals(1, catch_3.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(catch_3, 1))\n        assertCallInfosContainsUnique(catch_3, listOf(\"Proc\"), \"NilClass\")\n\n        val dont_catch_3 = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"dont_catch_3\"))\n        assertEquals(0, dont_catch_3.size)\n\n        val foo = RSignatureProviderImpl.getRegisteredCallInfos(createMethodInfo(\"Object\", \"foo\"))\n        assertEquals(1, foo.size)\n        assertTrue(allCallInfosHaveNumberOfUnnamedArguments(foo, 1))\n        assertCallInfosContainsUnique(foo, listOf(\"Proc\"), \"NilClass\")\n    }\n\n    private fun executeScript(runnableScriptName: String, additionalArgScannerArgs: Array<String> = emptyArray()) {\n        val url = javaClass.classLoader.getResource(runnableScriptName)\n\n        if (url == null) {\n            val e = RuntimeException(\"Cannot find script: $runnableScriptName\")\n            LOGGER.error(e)\n            throw e\n        }\n\n        val scriptPath = url.path\n        val module = myFixture.module\n\n        try {\n            LOGGER.warn(getProcessOutput(RubyCommandLine(RubyLocalRunner.getRunner(module), false)\n                    .withWorkDirectory(\"../arg_scanner\")\n                    .withExePath(\"rake\")\n                    .withParameters(\"install\")\n                    .createProcess()))\n\n            lastServer = SignatureServer()\n\n            val pipeFileName = lastServer!!.runServerAsync(true)\n\n            assertEquals(\"\", getProcessOutput(RubyCommandLine(RubyLocalRunner.getRunner(module), false)\n                    .withExePath(\"arg-scanner\")\n                    .withParameters(\"--pipe-file-path=$pipeFileName\", \"--type-tracker\",\n                            *additionalArgScannerArgs, \"ruby\", scriptPath)\n                    .createProcess()))\n        } catch (e: ExecutionException) {\n            LOGGER.error(e.message)\n            throw RuntimeException(e)\n        } catch (e: InterruptedException) {\n            LOGGER.error(e.message)\n            throw RuntimeException(e)\n        }\n\n    }\n\n    private fun waitForServer() {\n        try {\n            Thread.sleep(100)\n        } catch (ignored: InterruptedException) {\n        }\n\n        var cnt = 0\n        while (lastServer!!.isProcessingRequests() && cnt < 100) {\n            try {\n                Thread.sleep(1000)\n                cnt++\n            } catch (e: InterruptedException) {\n                throw RuntimeException(e)\n            }\n\n        }\n    }\n\n    private fun runAndGetCallInfos(executableScriptName: String,\n                                   methodInfo: MethodInfo): List<CallInfo> {\n        executeScript(executableScriptName)\n        waitForServer()\n        return RSignatureProviderImpl.getRegisteredCallInfos(methodInfo)\n    }\n\n    companion object {\n\n        private val LOGGER = Logger.getInstance(\"CallStatCompletionTest\")\n\n        @Throws(InterruptedException::class)\n        private fun getProcessOutput(process: Process): String {\n            //        final InputStream inputStream = process.getInputStream();\n            val errorStream = process.errorStream\n            process.waitFor(30, TimeUnit.SECONDS)\n            try {\n                return errorStream.bufferedReader().use { it.readText() }\n            } catch (e: IOException) {\n                throw RuntimeException(e)\n            }\n\n        }\n\n        private fun createMethodInfo(className: String, methodName: String): MethodInfo {\n            return MethodInfo(ClassInfo(className), methodName, RVisibility.PUBLIC)\n        }\n\n        private fun assertCallInfosContainsUnique(callInfos: List<CallInfo>,\n                                                  arguments: List<String>,\n                                                  returnType: String) {\n            val toAssert = callInfos.filter { callInfo ->\n                callInfo.unnamedArguments.map { it.type } == arguments && callInfo.returnType == returnType\n            }.count() == 1\n            Assert.assertTrue(\"\" +\n                    \"Expected \\n\" +\n                    \"${callInfos.joinToString(separator = \",\\n\")}\\n\" +\n                    \"contains unique ${arguments.joinToString(prefix = \"(\", postfix = \")\")} -> $returnType\", toAssert)\n        }\n\n        private fun allCallInfosHaveNumberOfUnnamedArguments(callInfos: List<CallInfo>, numberOfArguments: Int): Boolean {\n            return callInfos.all { it.unnamedArguments.size == numberOfArguments }\n        }\n    }\n}\n\n"
  },
  {
    "path": "ide-plugin/src/test/java/org/jetbrains/plugins/ruby/ruby/actions/ImportExportTests.kt",
    "content": "package org.jetbrains.plugins.ruby.ruby.actions\n\nimport junit.framework.Assert\nimport junit.framework.TestCase\nimport org.jetbrains.exposed.sql.Database\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoRow\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\nimport java.nio.file.Paths\nimport java.util.*\n\nclass ImportExportTests : TestCase() {\n\n    fun testSimpleExport() {\n        val data = (0 until 2 * CHUNK_SIZE + 1).map {\n            createCallInfo(\"A$it\", \"foo\", listOf(\"String\", \"Symbol\"), \"Integer\")\n        }\n\n        DatabaseProvider.connectToDB(generateTempDBFilePath(), isDefaultDatabase = true)\n\n        DatabaseProvider.defaultDatabaseTransaction {\n            data.forEach { CallInfoTable.insertInfoIfNotContains(it) }\n        }\n\n        val exportedDB = generateTempDBFilePath().let { pathToExport: String ->\n            ExportContractsAction.exportContractsToFile(pathToExport, moveProgressBar = false)\n\n            return@let DatabaseProvider.connectToDB(pathToExport)\n        }\n\n        Assert.assertEquals(DatabaseProvider.defaultDatabase!!.allCallInfos, exportedDB.allCallInfos)\n    }\n\n    fun testSimpleImport() {\n        val data = (0 until 2 * CHUNK_SIZE + 1).map {\n            createCallInfo(\"A$it\", \"foo\", listOf(\"String\", \"Symbol\"), \"Integer\")\n        }\n\n        DatabaseProvider.connectToDB(generateTempDBFilePath(), isDefaultDatabase = true)\n\n        val dbToImport = generateTempDBFilePath().let { pathToImport: String ->\n            val db = DatabaseProvider.connectToDB(pathToImport)\n\n            transaction(db) {\n                data.forEach { CallInfoTable.insertInfoIfNotContains(it) }\n            }\n\n            ImportContractsAction.importContractsFromFile(pathToImport, moveProgressBar = false)\n\n            return@let db\n        }\n\n        Assert.assertEquals(dbToImport.allCallInfos, DatabaseProvider.defaultDatabase!!.allCallInfos)\n    }\n\n    fun testImportWhenDefaultDBIsNotEmpty() {\n        val data = setOf(\n                createCallInfo(\"A\", \"foo\", listOf(\"String\", \"Symbol\"), \"Integer\"),\n                createCallInfo(\"B\", \"bar\", listOf(\"Integer\"), \"String\"),\n                createCallInfo(\"C\", \"foobar\", listOf(\"String\"), \"String\")\n        )\n\n        val defaultDBData = setOf(\n                createCallInfo(\"A\", \"foo\", listOf(\"String\", \"Symbol\"), \"Integer\"),\n                createCallInfo(\"B\", \"bar\", listOf(\"String\"), \"String\"),\n                createCallInfo(\"D\", \"baz\", listOf(\"Integer\"), \"String\"),\n                createCallInfo(\"E\", \"foobar\", listOf(\"String\", \"Symbol\"), \"String\")\n        )\n\n        DatabaseProvider.connectToDB(generateTempDBFilePath(), isDefaultDatabase = true)\n        DatabaseProvider.defaultDatabaseTransaction {\n            defaultDBData.forEach { CallInfoTable.insertInfoIfNotContains(it) }\n        }\n\n        val dbToImport = generateTempDBFilePath().let { pathToImport: String ->\n            val db = DatabaseProvider.connectToDB(pathToImport)\n\n            transaction(db) {\n                data.forEach { CallInfoTable.insertInfoIfNotContains(it) }\n            }\n\n            ImportContractsAction.importContractsFromFile(pathToImport, moveProgressBar = false)\n\n            return@let db\n        }\n\n        Assert.assertEquals(dbToImport.allCallInfos.union(defaultDBData), DatabaseProvider.defaultDatabase!!.allCallInfos)\n    }\n\n    private val Database.allCallInfos: Set<CallInfo>\n        get() = transaction(this) { CallInfoRow.all().map { it.copy() } }.toSet()\n\n    private fun createCallInfo(className: String, methodName: String, unnamedArgsTypes: List<String>, returnType: String): CallInfo {\n        val args = unnamedArgsTypes.mapIndexed { index, s -> ArgumentNameAndType(('a' + index).toString(), s) }\n        return CallInfoImpl(MethodInfo(ClassInfo(className), methodName, RVisibility.PUBLIC), emptyList(), args, returnType)\n    }\n\n    private fun generateTempDBFilePath(prefix: String = \"\"): String {\n        val dirForTempFiles = System.getProperty(\"java.io.tmpdir\")\n        return Paths.get(dirForTempFiles, prefix + UUID.randomUUID()).toString() + DatabaseProvider.H2_DB_FILE_EXTENSION\n    }\n}\n"
  },
  {
    "path": "ide-plugin/src/test/testData/anonymous_module_method_call_test.rb",
    "content": "module A\n  def self.foo(a, b)\n    true\n  end\nend\n\nA.foo(\"hey\", :symbol)"
  },
  {
    "path": "ide-plugin/src/test/testData/call_info_of_nested_class_test.rb",
    "content": "module M\n  class A\n    def foo(a)\n      a\n    end\n  end\nend\n\na = M::A.new\na.foo(a)"
  },
  {
    "path": "ide-plugin/src/test/testData/duplicates_in_callinfo_table_test.rb",
    "content": "def foo(a)\n  if a == \"str\"\n    return a\n  end\n  false\nend\n\nfoo(\"str\")\nfoo(\"not str\")\n3.times { foo(\"str\") }\n3.times { foo(false) }\n"
  },
  {
    "path": "ide-plugin/src/test/testData/forget_call_info_when_arguments_number_changed_test_part_1.rb",
    "content": "class A\n    def foo(a)\n        :symbol\n    end\nend\n\nA.new.foo(\"Hey\")\n"
  },
  {
    "path": "ide-plugin/src/test/testData/forget_call_info_when_arguments_number_changed_test_part_2.rb",
    "content": "class A\n    def foo(a, b)\n        b\n    end\nend\n\nA.new.foo(true, false)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/in_project_root_test/gem_like.rb",
    "content": "def catch(a); end\n\ndef dont_catch_2(a); end\n\ndef catch_2(a)\n  dont_catch_2(a)\nend\n\ndef dont_catch_3(&a)\n  yield(a)\nend\n\ndef catch_3(&a)\n  dont_catch_3(&a)\nend\n"
  },
  {
    "path": "ide-plugin/src/test/testData/in_project_root_test/in_project_root_test.rb",
    "content": "require_relative 'gem_like'\n\ncatch('hey')\n\ncatch_2('bro')\n\ndef foo(a); end\n\ncatch_3(&method(:foo))\n"
  },
  {
    "path": "ide-plugin/src/test/testData/merge_test1.rb",
    "content": "class A\n\nend\n\nclass C\n\nend\n\nclass B1\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nclass B2\n  def test3\n\n  end\n\n  def test4\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo1(a, b)\n    B1.new\nend\nFoo\n\n\nA.new.doo1(C.new, C.new)\nA.new.doo1(C.new, C.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/merge_test1_to_run.rb",
    "content": "class A\n\nend\n\nclass C\n\nend\n\nclass B1\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nclass B2\n  def test3\n\n  end\n\n  def test4\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo1(a, b)\n    B1.new\nend\nFoo\n\n\nA.new.doo1(C.new, C.new)\nA.new.doo1(C.new, C.new)"
  },
  {
    "path": "ide-plugin/src/test/testData/merge_test2.rb",
    "content": "class A\n\nend\n\nclass C\n\nend\n\nclass B1\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nclass B2\n  def test3\n\n  end\n\n  def test4\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo2(a, b)\n    B2.new\nend\nFoo\n\n\nA.new.doo2(C.new, C.new)\nA.new.doo2(C.new, C.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/merge_test2_to_run.rb",
    "content": "class A\n\nend\n\nclass C\n\nend\n\nclass B1\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nclass B2\n  def test3\n\n  end\n\n  def test4\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo2(a, b)\n    B2.new\nend\nFoo\n\n\nA.new.doo2(C.new, C.new)\nA.new.doo2(C.new, C.new)"
  },
  {
    "path": "ide-plugin/src/test/testData/method_without_parameters_test.rb",
    "content": "def foo\n  \"hey\"\nend\n\nfoo"
  },
  {
    "path": "ide-plugin/src/test/testData/multiple_execution_test1.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo2(a)\n  a\nend\nFoo\n\nx = A.new.foo2(1)\ny = A.new.foo2('1')"
  },
  {
    "path": "ide-plugin/src/test/testData/multiple_execution_test2.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo2(a)\n  a\nend\nFoo\n\nx = A.new.foo2(Date.new)\nx = A.new.foo2(B.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/multiple_execution_test2_to_run.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo2(a)\n  a\nend\nFoo\n\nx = A.new.foo2(Date.new)\nx = A.new.foo2(B.new)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/ref_links_test.rb",
    "content": "class A\n\nend\n\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo(a, b, c)\n  a\nend\nFoo\n\nA.new.doo('1', '2', '3')\nA.new.doo(1, '2', 3)\nA.new.doo(B.new, A.new, B.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/ref_links_test_to_run.rb",
    "content": "class A\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef doo(a, b, c)\n  a\nend\nFoo\n\nA.new.doo('1', '2', '3')\nA.new.doo(1, '2', 3)\nA.new.doo(B.new, A.new, B.new)"
  },
  {
    "path": "ide-plugin/src/test/testData/ruby_exec_part_2.rb",
    "content": "def bar(a); end\n\nbar(true)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/ruby_exec_test.rb",
    "content": "def foo(a); end\n\nfoo(\"string\")\n\nKernel.exec(\"ruby\", \"#{File.expand_path(\"..\", __FILE__)}/ruby_exec_part_2.rb\")\n"
  },
  {
    "path": "ide-plugin/src/test/testData/sample_kw_test.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo1(kw: a)\n  p '!'\n  B.new\nend\nFoo\n\nx = A.new.foo1(kw: C.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/sample_kw_test_to_run.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo1(kw: a)\n  p '!'\n  B.new\nend\nFoo\n\nx = A.new.foo1(kw: C.new)"
  },
  {
    "path": "ide-plugin/src/test/testData/sample_test.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo(a)\n  B.new\nend\nFoo\n\nx = A.new.foo(C.new).<caret>"
  },
  {
    "path": "ide-plugin/src/test/testData/sample_test_to_run.rb",
    "content": "require 'date'\n\nclass A\n\nend\n\nclass C\n\nend\n\nclass B\n  def test1\n\n  end\n\n  def test2\n\n  end\nend\n\nA.class_eval <<Foo\ndef foo(a)\n  B.new\nend\nFoo\n\nx = A.new.foo(C.new)"
  },
  {
    "path": "ide-plugin/src/test/testData/save_types_between_launches_test_part_1.rb",
    "content": "class A\n    def foo(a)\n        if a == \"str1\"\n            return :symbol\n        end\n        if a == \"str2\"\n            return /some regex/\n        end\n        if a.kind_of? Class\n            return A.new\n        end\n        if a.kind_of? TrueClass\n            return false\n        end\n    end\nend\n\na = A.new\n\na.foo(\"str1\")\na.foo(String)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/save_types_between_launches_test_part_2.rb",
    "content": "class A\n    def foo(a)\n        if a == \"str1\"\n            return :symbol\n        end\n        if a == \"str2\"\n            return /some regex/\n        end\n        if a.kind_of? Class\n            return A.new\n        end\n        if a.kind_of? TrueClass\n            return false\n        end\n    end\nend\n\na = A.new\n\na.foo(true)\na.foo(\"str2\")\n"
  },
  {
    "path": "ide-plugin/src/test/testData/simple_call_info_collection_test.rb",
    "content": "class AClass\n    def foo(a)\n        if a.kind_of? String\n            :symbol\n        else\n            true\n        end\n    end\nend\n\nAClass.new.foo(\"String\")\n"
  },
  {
    "path": "ide-plugin/src/test/testData/simple_call_info_collection_test_multiple_functions_test.rb",
    "content": "class A\n    def foo(a, b)\n        a || b\n    end\n\n    def bar(a)\n        a && A.new\n    end\nend\n\na = A.new\n\na.foo(\"Hey\", String)\n\na.bar(true)\na.bar(false)\na.bar(:symbol)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/simple_call_info_collection_with_multiple_arguments_test.rb",
    "content": "class AClass\n    def foo(a, b)\n        /some regex/\n    end\nend\n\nAClass.new.foo(\"String\", true)\n"
  },
  {
    "path": "ide-plugin/src/test/testData/top_level_methods_call_info_collection_test.rb",
    "content": "def foo(a, b)\n    if a == \"str\"\n      return /some regex/\n    end\n    a || b\nend\n\nfoo(true, false)\nfoo(false, :symbol)\nfoo(\"str\", true)\nfoo(\"not str\", true)"
  },
  {
    "path": "ruby-call-signature/build.gradle",
    "content": "apply plugin: 'java'\n\nsourceSets {\n    main.java.srcDirs = ['src/main/java']\n    test.java.srcDirs = ['src/test/java']\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/CallInfo.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nconst val ARGUMENTS_TYPES_SEPARATOR = \";\"\n\ninterface CallInfo {\n    val methodInfo: MethodInfo\n\n    /**\n     * Types of unnamed arguments (e.g. REQ, OPT, REST, POST)\n     */\n    val unnamedArguments: List<ArgumentNameAndType>\n\n    /**\n     * Types of named arguments sorted alphabetically by [ArgumentNameAndType.name]\n     */\n    val namedArguments: List<ArgumentNameAndType>\n\n    val returnType: String\n\n    /**\n     * Join [unnamedArguments] to raw [String] which is used in database\n     */\n    fun unnamedArgumentsTypesJoinToRawString(): String\n\n    /**\n     * Join [namedArgumentsJoinToRawString] to raw [String] which is used in database.\n     * Should return concatenated string containing elements ordered by argument name alphabetically\n     */\n    fun namedArgumentsJoinToRawString(): String\n\n    fun getTypeNameByArgumentName(name: String): String? {\n        return (unnamedArguments.find { it.name == name } ?: namedArguments.find { it.name == name })?.type\n    }\n}\n\ndata class ArgumentNameAndType(val name: String, val type: String) {\n    companion object {\n        const val NAME_AND_TYPE_SEPARATOR = \",\"\n        /**\n         * For such method:\n         * def foo(a, b = 1); end\n         *\n         * And such call:\n         * foo(a)\n         * `b` is implicitly passed\n         */\n        const val IMPLICITLY_PASSED_ARGUMENT_TYPE = \"-\"\n    }\n}\n\nclass CallInfoImpl(override val methodInfo: MethodInfo,\n                   namedArguments: List<ArgumentNameAndType>,\n                   override val unnamedArguments: List<ArgumentNameAndType>,\n                   override val returnType: String) : CallInfo {\n    override val namedArguments = namedArguments.sortedBy { it.name }\n\n    override fun namedArgumentsJoinToRawString(): String =\n            namedArguments.joinToString(separator = ARGUMENTS_TYPES_SEPARATOR) { it.name + \",\" + it.type }\n\n    override fun unnamedArgumentsTypesJoinToRawString(): String =\n            unnamedArguments.joinToString(separator = ARGUMENTS_TYPES_SEPARATOR) { it.name + \",\" + it.type }\n\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (other !is CallInfo) return false\n\n        other as CallInfoImpl\n\n        return methodInfo == other.methodInfo &&\n               unnamedArguments == other.unnamedArguments &&\n               returnType == other.returnType &&\n               namedArguments == other.namedArguments\n    }\n\n    override fun hashCode(): Int {\n        var result = methodInfo.hashCode()\n        result = 31 * result + unnamedArguments.hashCode()\n        result = 31 * result + returnType.hashCode()\n        result = 31 * result + namedArguments.hashCode()\n        return result\n    }\n\n    override fun toString(): String {\n        return \"CallInfoIml(methodInfo=$methodInfo, namedArguments=$namedArguments, unnamedArguments=$unnamedArguments, returnType=$returnType)\"\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/ClassInfo.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\n\ninterface ClassInfo {\n    val gemInfo: GemInfo?\n    val classFQN: String\n    \n\n    data class Impl(override val gemInfo: GemInfo?, override val classFQN: String) : ClassInfo\n\n    fun validate(): Boolean {\n        if (classFQN.length > LENGTH_OF_FQN) {\n            return false\n        }\n        val gemInfoVal = gemInfo\n        return gemInfoVal == null || gemInfoVal.validate()\n    }\n\n    companion object {\n        val LENGTH_OF_FQN = 200\n    }\n\n}\n\n\nfun ClassInfo(gemInfo: GemInfo?, classFQN: String) = ClassInfo.Impl(gemInfo, classFQN)\n\nfun ClassInfo(classFQN: String) = ClassInfo.Impl(null, classFQN)\n\nfun ClassInfo(copy: ClassInfo) = with(copy) { ClassInfo.Impl(gemInfo?.let { GemInfo(it) }, classFQN) }\n\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/GemInfo.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\ninterface GemInfo {\n    val name: String\n    val version: String\n\n    data class Impl(override val name: String, override val version: String) : GemInfo\n\n    fun validate(): Boolean {\n        return name.length <= LENGTH_OF_GEMNAME &&\n                version.length <= LENGTH_OF_GEMVERSION\n    }\n\n    companion object {\n        val NONE = Impl(\"\", \"\")\n        val LENGTH_OF_GEMNAME = 50\n        val LENGTH_OF_GEMVERSION = 50\n    }\n}\n\nfun GemInfo(name: String, version: String) = GemInfo.Impl(name, version)\n\nfun GemInfo(copy: GemInfo) = with(copy) { GemInfo.Impl(name, version) }\n\nfun GemInfoOrNull(name: String, version: String) = GemInfo(name, version).let { if (it == GemInfo.NONE) null else it}\n\nfun gemInfoFromFilePathOrNull(path: String): GemInfo? {\n    val gemPathPattern = \"\"\"([A-Za-z0-9_-]+)-(\\d+[0-9A-Za-z.]+)\"\"\"\n    val regex = Regex(gemPathPattern)\n    val (gemName, gemVersion) = regex.findAll(path).lastOrNull()?.destructured ?: return null\n    return GemInfo(gemName, gemVersion)\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/MethodInfo.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\ninterface MethodInfo {\n    val classInfo: ClassInfo\n    val name: String\n    val visibility: RVisibility\n    val location: Location?\n\n    data class Impl(override val classInfo: ClassInfo,\n                    override val name: String,\n                    override val visibility: RVisibility = RVisibility.PUBLIC,\n                    override val location: Location? = null) : MethodInfo\n\n    fun validate(): Boolean {\n        if (name.length > LENGTH_OF_NAME) {\n            return false\n        }\n        val loc = location\n        if (loc == null || loc.path.length > LENGTH_OF_PATH) {\n            return false\n        }\n        return classInfo.validate()\n    }\n\n    companion object {\n        val LENGTH_OF_NAME = 100\n        val LENGTH_OF_PATH = 1000\n    }\n}\n\n@JvmOverloads\nfun MethodInfo(classInfo: ClassInfo, name: String, visibility: RVisibility, location: Location? = null) =\n        MethodInfo.Impl(classInfo, name, visibility, location)\n\nfun MethodInfo(copy: MethodInfo) = with(copy) { MethodInfo.Impl(ClassInfo(classInfo), name, visibility, location) }\n\ndata class Location(val path: String, val lineno: Int)\n\nenum class RVisibility constructor(val value: Byte, val presentableName: String) {\n    PRIVATE(0, \"PRIVATE\"),\n    PROTECTED(1, \"PROTECTED\"),\n    PUBLIC(2, \"PUBLIC\");\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/ParameterInfo.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature;\n\nimport org.jetbrains.annotations.NotNull;\n\npublic class ParameterInfo {\n    @NotNull\n    private final String myName;\n    @NotNull\n    private final ParameterInfo.Type myModifier;\n\n    public ParameterInfo(@NotNull final String name, @NotNull final Type modifier) {\n        myName = name;\n        myModifier = modifier;\n    }\n\n    @NotNull\n    public String getName() {\n        return myName;\n    }\n\n    @NotNull\n    public ParameterInfo.Type getModifier() {\n        return myModifier;\n    }\n\n    public boolean isNamedParameter() {\n        return myModifier == Type.KEY || myModifier == Type.KEYREQ || myModifier == Type.KEYREST;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        final ParameterInfo that = (ParameterInfo) o;\n\n        //noinspection SimplifiableIfStatement\n        if (!myName.equals(that.myName)) return false;\n        return myModifier == that.myModifier;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = myName.hashCode();\n        result = 31 * result + myModifier.hashCode();\n        return result;\n    }\n\n    // parameter info:\n    //\n    // def foo(a,     # mandatory (REQ)\n    //         b=1,   # optional (OPT)\n    //         *c,    # rest (REST)\n    //         d,     # post (POST)\n    //         e:,    # keywords (KEYREQ)\n    //         f:1,   # optional keywords (KEY)\n    //         **g,   # rest keywords (KEYREST)\n    //         &h)    # block\n    public enum Type {\n        REQ,\n        OPT,\n        POST,\n        REST,\n        KEYREQ,\n        KEY,\n        KEYREST,\n        BLOCK,\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/RSignatureContract.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature;\n\nimport kotlin.Pair;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.annotations.TestOnly;\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ContractTransition;\n\nimport java.util.*;\n\nimport static org.jetbrains.ruby.codeInsight.types.signature.contractTransition.TransitionHelper.calculateTransition;\n\npublic class RSignatureContract implements SignatureContract {\n\n    @NotNull\n    private final RSignatureContractNode myStartContractNode;\n    @NotNull\n    private final List<ParameterInfo> myArgsInfo;\n    @NotNull\n    private final List<List<RSignatureContractNode>> myLevels;\n    @NotNull\n    private final SignatureNode myTermNode;\n\n    public RSignatureContract(@NotNull RTuple tuple) {\n        myArgsInfo = tuple.getArgsInfo();\n        myLevels = new ArrayList<>(getArgsInfo().size() + 2);\n        for (int i = 0; i < getArgsInfo().size() + 2; i++) {\n            myLevels.add(new ArrayList<>());\n        }\n\n        myStartContractNode = Objects.requireNonNull(createNodeAndAddToLevels(0));\n\n        myTermNode = Objects.requireNonNull(createNodeAndAddToLevels(myLevels.size() - 1));\n\n        addRTuple(tuple);\n    }\n\n    public RSignatureContract(@NotNull List<ParameterInfo> argsInfo,\n                              @NotNull RSignatureContractNode startContractNode,\n                              @NotNull SignatureNode termNode,\n                              @NotNull List<List<RSignatureContractNode>> levels) {\n        myStartContractNode = startContractNode;\n        myArgsInfo = argsInfo;\n        myLevels = levels;\n        myTermNode = termNode;\n\n        // TODO recalculate mask\n    }\n\n    private RSignatureContract(@NotNull SignatureContract source) {\n        myArgsInfo = source.getArgsInfo();\n        myLevels = new ArrayList<>(getArgsInfo().size() + 2);\n        for (int i = 0; i < getArgsInfo().size() + 2; i++) {\n            myLevels.add(new ArrayList<>());\n        }\n\n        final Map<SignatureNode, kotlin.Pair<RSignatureContractNode, Integer>> oldNodesToNewWithLayerNumber = new HashMap<>();\n        final Queue<SignatureNode> q = new ArrayDeque<>();\n\n        final RSignatureContractNode newStartNode = Objects.requireNonNull(createNodeAndAddToLevels(0));\n        myLevels.get(0).add(newStartNode);\n        oldNodesToNewWithLayerNumber.put(newStartNode, new kotlin.Pair<>(newStartNode, 0));\n        q.add(source.getStartNode());\n\n        while (!q.isEmpty()) {\n            final SignatureNode oldSourceNode = q.poll();\n            final kotlin.Pair<RSignatureContractNode, Integer> newSourceNodeAndLevel = oldNodesToNewWithLayerNumber.get(oldSourceNode);\n\n            oldSourceNode.getTransitions().forEach((contractTransition, oldTargetNode) -> {\n                final kotlin.Pair<RSignatureContractNode, Integer> newTargetNodeWithLayer =\n                        oldNodesToNewWithLayerNumber.computeIfAbsent(oldTargetNode, old -> {\n                            final RSignatureContractNode newNode = createNodeAndAddToLevels(newSourceNodeAndLevel.getSecond() + 1);\n                            q.add(newNode);\n                            return new kotlin.Pair<>(\n                                    newNode,\n                                    newSourceNodeAndLevel.getSecond() + 1\n                            );\n                        });\n\n                newSourceNodeAndLevel.getFirst().addLink(contractTransition, newTargetNodeWithLayer.getFirst());\n            });\n        }\n\n        myStartContractNode = newStartNode;\n\n        if (myLevels.get(myLevels.size() - 1).size() != 1) {\n            throw new AssertionError(\"Incorrect # of nodes on the last level: \"\n                    + myLevels.get(myLevels.size() - 1));\n        }\n        myTermNode = myLevels.get(myLevels.size() - 1).iterator().next();\n    }\n\n    @NotNull\n    @Override\n    public RSignatureContractNode getStartNode() {\n        return myStartContractNode;\n    }\n\n    @NotNull\n    @Override\n    public List<ParameterInfo> getArgsInfo() {\n        return myArgsInfo;\n    }\n\n    public int getNodeCount() {\n        return myLevels.stream().map(List::size).reduce(0, (a, b) -> a + b);\n    }\n\n    @NotNull\n    public synchronized SignatureContract copy() {\n        final Map<SignatureNode, RSignatureContractNode> oldToNew = new HashMap<>();\n\n        RSignatureContractNode newStartNode = new RSignatureContractNode();\n        oldToNew.put(myStartContractNode, newStartNode);\n\n        for (int i = 0; i < myLevels.size() - 1; ++i) {\n            for (final RSignatureContractNode oldSourceNode : myLevels.get(i)) {\n\n                final RSignatureContractNode newSourceNode = oldToNew.get(oldSourceNode);\n                oldSourceNode.getTransitions().forEach((transition, oldTargetNode) -> {\n                    final RSignatureContractNode newTargetNode = oldToNew.computeIfAbsent(oldTargetNode,\n                            (x) -> new RSignatureContractNode());\n                    newSourceNode.addLink(transition, newTargetNode);\n                });\n            }\n        }\n\n        return new Immutable(newStartNode, oldToNew.size(), myArgsInfo);\n    }\n\n    /**\n     * @return true if succeeded; false otherwise\n     */\n    public synchronized boolean addRTuple(@NotNull RTuple tuple) {\n        final List<String> argsTypes = tuple.getArgsTypes();\n        if (argsTypes.size() != myArgsInfo.size()) {\n            return false;\n        }\n\n        String returnType = tuple.getReturnTypeName();\n\n        RSignatureContractNode currNode = myStartContractNode;\n        for (int argIndex = 0; argIndex < argsTypes.size(); argIndex++) {\n            final String type = argsTypes.get(argIndex);\n\n            final ContractTransition transition = calculateTransition(tuple.getArgsTypes(), argIndex, type);\n\n            if (!currNode.getTransitions().containsKey(transition)) {\n                final RSignatureContractNode newNode = createNodeAndAddToLevels(argIndex + 1);\n                if (newNode == null) {\n                    return false;\n                }\n\n                currNode.addLink(transition, newNode);\n\n                currNode = newNode;\n            } else {\n\n                currNode = ((RSignatureContractNode) currNode.getTransitions().get(transition));\n            }\n        }\n\n        final ContractTransition transition = calculateTransition(tuple.getArgsTypes(), tuple.getArgsTypes().size(), returnType);\n\n        currNode.addLink(transition, myTermNode);\n        return true;\n    }\n\n    synchronized void minimize() {\n        int numberOfLevels = myLevels.size();\n\n        for (int i = numberOfLevels - 1; i > 0; i--) {\n            List<RSignatureContractNode> level = myLevels.get(i);\n\n            HashMap<SignatureNode, SignatureNode> representatives = new HashMap<>();\n            Set<SignatureNode> uselessVertices = new HashSet<>();\n\n            for (SignatureNode node : level) {\n                representatives.put(node, node);\n            }\n\n            for (int v1 = 0; v1 < level.size(); v1++) {\n                for (int v2 = v1 + 1; v2 < level.size(); v2++) {\n                    SignatureNode vertex1 = level.get(v1);\n                    SignatureNode vertex2 = level.get(v2);\n\n                    boolean isSame = vertex1.getTransitions().size() == vertex2.getTransitions().size();\n\n                    for (ContractTransition transition : vertex1.getTransitions().keySet()) {\n\n                        if (!vertex2.getTransitions().containsKey(transition) || vertex1.getTransitions().get(transition) != vertex2.getTransitions().get(transition)) {\n                            isSame = false;\n                        }\n                    }\n\n                    if (isSame) {\n                        SignatureNode vertex1presenter = representatives.get(vertex1);\n                        representatives.put(vertex2, vertex1presenter);\n                        uselessVertices.add(vertex2);\n                    }\n                }\n            }\n\n            List<RSignatureContractNode> prevLevel = myLevels.get(i - 1);\n\n\n            if (!uselessVertices.isEmpty()) {\n                for (RSignatureContractNode node : prevLevel) {\n                    for (ContractTransition transition : node.getTransitions().keySet()) {\n                        RSignatureContractNode child = ((RSignatureContractNode) node.getTransitions().get(transition));\n                        node.addLink(transition, representatives.get(child));\n                    }\n                }\n            }\n\n            //noinspection SuspiciousMethodCalls\n            level.removeAll(uselessVertices);\n        }\n    }\n\n    @TestOnly\n    @NotNull\n    public List<List<RSignatureContractNode>> getLevels() {\n        return myLevels;\n    }\n\n    private void AddToBfsQueueAndUse(@NotNull SignatureNode oldNode, @NotNull SignatureNode newNode, @NotNull Queue<Pair<PairOfNodes, Integer>> bfsQueue, @NotNull Set<PairOfNodes> used, Integer level) {\n        PairOfNodes newPairOfNodes = new PairOfNodes(oldNode, newNode);\n\n        if (!used.contains(newPairOfNodes)) {\n            used.add(newPairOfNodes);\n            bfsQueue.add(new Pair<>(newPairOfNodes, level));\n        }\n    }\n\n    /**\n     * @return true if succeeded; false otherwise\n     */\n    public synchronized boolean mergeWith(@NotNull SignatureContract additive) {\n        // TODO synchronize on additive (can't do this plainly due to the possible deadlock)???\n        Set<PairOfNodes> used = new HashSet<>();\n        Queue<Pair<PairOfNodes, Integer>> bfsQueue = new LinkedList<>();\n        PairOfNodes startPairOfNodes = new PairOfNodes(getStartNode(), additive.getStartNode());\n        bfsQueue.add(new Pair<>(startPairOfNodes, 0));\n\n        while (!bfsQueue.isEmpty()) {\n            Pair<PairOfNodes, Integer> currItem = bfsQueue.poll();\n            SignatureNode oldNode = currItem.getFirst().myOldNode;\n            SignatureNode newNode = currItem.getFirst().myNewNode;\n            Integer level = currItem.getSecond();\n\n            Map<SignatureNode, Integer> childNodesWithPows = new HashMap<>();\n\n            for (ContractTransition transition : oldNode.getTransitions().keySet()) {\n                SignatureNode node = oldNode.getTransitions().get(transition);\n\n                if (childNodesWithPows.containsKey(node)) {\n                    Integer oldPow = childNodesWithPows.get(node);\n                    childNodesWithPows.put(node, oldPow + 1);\n                } else {\n                    childNodesWithPows.put(node, 1);\n                }\n            }\n\n            for (ContractTransition transition : newNode.getTransitions().keySet()) {\n\n                if (oldNode.getTransitions().containsKey(transition)) {\n                    SignatureNode node = oldNode.getTransitions().get(transition);\n                    if (childNodesWithPows.get(node) == 1) {\n                        AddToBfsQueueAndUse(node, newNode.getTransitions().get(transition), bfsQueue, used, level + 1);\n                        continue;\n                    }\n\n                    Integer oldPow = childNodesWithPows.get(node);\n                    childNodesWithPows.put(node, oldPow - 1);\n                }\n\n                RSignatureContractNode node = createNodeAndAddToLevels(level + 1);\n                if (node == null) {\n                    return false;\n                }\n\n                if (oldNode.getTransitions().keySet().contains(transition)) {\n                    SignatureNode nodeToClone = oldNode.getTransitions().get(transition);\n\n                    for (ContractTransition contractTransition : nodeToClone.getTransitions().keySet()) {\n                        node.getTransitions().put(contractTransition, nodeToClone.getTransitions().get(contractTransition));\n                    }\n                }\n                oldNode.getTransitions().put(transition, node);\n\n                AddToBfsQueueAndUse(node, newNode.getTransitions().get(transition), bfsQueue, used, level + 1);\n            }\n        }\n\n        minimize();\n        return true;\n    }\n\n    /**\n     * @return newly created {@link RSignatureContract} if index in 0 (inclusively) until myLevels.size() (exclusively);\n     * otherwise {@code null}\n     */\n    @Nullable\n    private RSignatureContractNode createNodeAndAddToLevels(int index) {\n        if (index >= myLevels.size()) {\n            return null;\n        }\n\n        //TODO\n        if(index == myLevels.size() - 1 && !myLevels.get(index).isEmpty()) {\n            return myLevels.get(index).get(0);\n        }\n\n        RSignatureContractNode newNode = new RSignatureContractNode();\n\n        myLevels.get(index).add(newNode);\n        return newNode;\n    }\n\n    @Nullable\n    public static RSignatureContract mergeMutably(@NotNull SignatureContract first, @NotNull SignatureContract second) {\n        if (first instanceof RSignatureContract) {\n            if (((RSignatureContract) first).mergeWith(second)) {\n                return ((RSignatureContract) first);\n            } else {\n                return null;\n            }\n        } else {\n            return mergeMutably(new RSignatureContract(first), second);\n        }\n    }\n\n    private static class Immutable implements SignatureContract {\n        @NotNull\n        private final SignatureNode myStartNode;\n\n        private final int myNodeCount;\n        @NotNull\n        private final List<ParameterInfo> myArgsInfo;\n\n\n        private Immutable(@NotNull SignatureNode startNode, int nodeCount, @NotNull List<ParameterInfo> argsInfo) {\n            myStartNode = startNode;\n            myNodeCount = nodeCount;\n            myArgsInfo = argsInfo;\n        }\n\n        @Override\n        public int getNodeCount() {\n            return myNodeCount;\n        }\n\n        @NotNull\n        @Override\n        public SignatureNode getStartNode() {\n            return myStartNode;\n        }\n\n        @NotNull\n        @Override\n        public List<ParameterInfo> getArgsInfo() {\n            return myArgsInfo;\n        }\n    }\n\n    private static class PairOfNodes {\n        @NotNull\n        private final SignatureNode myOldNode;\n        @NotNull\n        private final SignatureNode myNewNode;\n\n        @NotNull\n        PairOfNodes pairGoByTransition(@NotNull ContractTransition transition) {\n            return new PairOfNodes(myOldNode.getTransitions().get(transition), myNewNode.getTransitions().get(transition));\n        }\n\n        PairOfNodes(@NotNull SignatureNode node1, @NotNull SignatureNode node2) {\n            myOldNode = node1;\n            myNewNode = node2;\n        }\n    }\n}\n\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/RSignatureContractContainer.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nclass RSignatureContractContainer {\n\n    private val myContracts: MutableMap<MethodInfo, RSignatureContract> = HashMap()\n    private val myNumberOfCalls: MutableMap<MethodInfo, Int> = HashMap()\n\n    fun acceptTuple(tuple: RTuple): Boolean {\n        val currInfo = tuple.methodInfo\n\n        val contract = myContracts[currInfo]\n        return contract != null && tuple.argsInfo == contract.argsInfo && SignatureContract.accept(contract, tuple)\n    }\n\n    fun addTuple(tuple: RTuple) {\n        val currInfo = tuple.methodInfo\n\n        if (myContracts.containsKey(currInfo)) {\n            val contract = myContracts[currInfo]\n\n            if (tuple.argsInfo.size == contract?.argsInfo?.size) {\n                contract.addRTuple(tuple)\n                myNumberOfCalls.compute(currInfo) { _, oldNumber -> (oldNumber ?: 0) + 1 }\n            }\n        } else {\n            val contract = RSignatureContract(tuple)\n            myContracts.put(currInfo, contract)\n        }\n    }\n\n    val registeredMethods: Set<MethodInfo>\n        get() = myContracts.keys\n\n    fun getSignature(info: MethodInfo): RSignatureContract? {\n        return myContracts[info]?.apply { minimize() }\n    }\n\n    fun clear() {\n        myContracts.clear()\n    }\n\n    val size: Int\n        get() = myContracts.size\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/RSignatureContractNode.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ContractTransition;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class RSignatureContractNode implements SignatureNode {\n\n    @NotNull\n    private final Map<ContractTransition, SignatureNode> myTransitions;\n\n    public RSignatureContractNode() {\n        myTransitions = new HashMap<>();\n    }\n\n    public void addLink(final @NotNull ContractTransition transition, @NotNull SignatureNode arrivalNode) {\n        myTransitions.put(transition, arrivalNode);\n    }\n\n    @NotNull\n    @Override\n    public Map<ContractTransition, SignatureNode> getTransitions() {\n        return myTransitions;\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/RTuple.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\npublic class RTuple {\n\n    @NotNull\n    private final MethodInfo myMethodInfo;\n\n    @NotNull\n    private final List<ParameterInfo> myArgsInfo;\n    @NotNull\n    private final List<String> myArgsTypes;\n    @NotNull\n    private final String myReturnTypeName;\n\n    public RTuple(@NotNull final MethodInfo methodInfo,\n                  @NotNull final List<ParameterInfo> argsInfo,\n                  @NotNull final List<String> argsTypeName,\n                  @NotNull final String returnTypeName) {\n        myMethodInfo = methodInfo;\n        myArgsInfo = argsInfo;\n        myArgsTypes = argsTypeName;\n        myReturnTypeName = returnTypeName;\n    }\n\n    @NotNull\n    public MethodInfo getMethodInfo() {\n        return myMethodInfo;\n    }\n\n    @NotNull\n    public List<ParameterInfo> getArgsInfo() {\n        return myArgsInfo;\n    }\n\n    @NotNull\n    List<String> getArgsTypes() {\n        return myArgsTypes;\n    }\n\n    @NotNull\n    String getReturnTypeName() {\n        return myReturnTypeName;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        RTuple that = (RTuple) o;\n\n        return myMethodInfo.equals(that.myMethodInfo) &&\n                myArgsInfo.equals(that.myArgsInfo) &&\n                myArgsTypes.equals(that.myArgsTypes);\n\n    }\n\n    @Override\n    public int hashCode() {\n        int result = myMethodInfo.hashCode();\n        result = 31 * result + myArgsInfo.hashCode();\n        result = 31 * result + myArgsTypes.hashCode();\n        return result;\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/SignatureContract.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ContractTransition\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ReferenceContractTransition\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.TransitionHelper\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.TypedContractTransition\nimport java.util.*\nimport kotlin.collections.HashMap\nimport kotlin.collections.HashSet\n\n/**\n * The `SignatureContract` interface allows for checking input type sequence validity\n * as well as hinting the next possible transitions for the current sequence.\n *\n * The set of type contracts representing the method is represented with\n * an automaton of a specific kind:\n *   * There is exactly one start node (=state) as an entry point for each\n *     type sequence;\n *   * There is exactly one finish node (=state) representing a successful\n *     read of the type sequence;\n *   * All paths from start node the the finish node have the same length.\n *\n * There is no difference between input type and return type in the means\n * of the automaton used. Thus,\n *\n *  * A set of input and output types `(A, B) -> C` is read in the contract iff\n *     1. automaton \"length\" is 3, and\n *     2. reading types `(A, B, C)` by the automaton succeeds.\n *  * Return type for input types `(A, B)` is calculated by reading `(A, B)`\n *     in the automaton and getting _the only_ outbound transition from the resulting node.\n */\ninterface SignatureContract {\n    val nodeCount: Int\n    val startNode: SignatureNode\n    val argsInfo: List<ParameterInfo>\n\n    companion object {\n        fun accept(rSignatureContract: SignatureContract, signature: RTuple): Boolean {\n            var currNode = rSignatureContract.startNode\n\n            val returnType = signature.returnTypeName\n\n            val argsTypes = signature.argsTypes\n            for (argIndex in argsTypes.indices) {\n                val type = argsTypes[argIndex]\n\n                val transition = TransitionHelper.calculateTransition(signature.argsTypes, argIndex, type)\n\n                currNode = currNode.transitions[transition]\n                        ?: return false\n            }\n\n            val transition = TransitionHelper.calculateTransition(signature.argsTypes, signature.argsTypes.size, returnType)\n\n            return currNode.transitions.containsKey(transition)\n        }\n\n        fun getAllReturnTypes(rSignatureContract: SignatureContract): Set<String> {\n            val curNode = rSignatureContract.startNode\n            return forwardLook(curNode)\n        }\n\n        private fun getBackEdges(startNode: SignatureNode): Map<SignatureNode, Map<ContractTransition, SignatureNode>> {\n            val result = HashMap<SignatureNode, MutableMap<ContractTransition, SignatureNode>>()\n            val queue = LinkedList<SignatureNode>()\n            val visited = HashSet<SignatureNode>()\n            queue.push(startNode)\n            visited.add(startNode)\n            while (!queue.isEmpty()) {\n                val node = queue.poll()\n                for ((transition, succ) in node.transitions) {\n                    if (!visited.contains(succ)) {\n                        var nodeEntry = result[succ]\n                        if (nodeEntry == null) {\n                            nodeEntry = HashMap()\n                            result.put(succ, nodeEntry)\n                        }\n                        nodeEntry.put(transition, node)\n                        visited.add(succ)\n                        queue.push(succ)\n                    }\n                }\n            }\n            return result\n        }\n\n        private fun forwardLook(startNode: SignatureNode): Set<String> {\n            val backEdges = getBackEdges(startNode)\n            val queue = LinkedList<SignatureNode>()\n            val visited = HashSet<SignatureNode>()\n            val level = HashMap<SignatureNode, Int>()\n            val result = HashSet<String>()\n\n            queue.push(startNode)\n            visited.add(startNode)\n            level[startNode] = 0\n\n            while (!queue.isEmpty()) {\n                val signatureNode = queue.poll()\n                for ((key, value) in signatureNode.transitions) {\n                    // is it exit node?\n                    if (value.transitions.isEmpty()) {\n                        when (key) {\n                            is TypedContractTransition -> result.add(key.type)\n                            is ReferenceContractTransition -> result.addAll(\n                                    backwardLook(signatureNode,\n                                            level[signatureNode]!! - getHighestSetBit(key.mask),\n                                            level[signatureNode]!!, backEdges))\n                            else -> throw IllegalStateException()\n                        }\n                    } else if (!visited.contains(value)) {\n                        visited.add(value)\n                        level[value] = level[signatureNode]!! + 1\n                        queue.add(value)\n                    }\n                }\n            }\n            return result\n        }\n\n        private fun getHighestSetBit(mask: Int): Int {\n            var m = mask\n            var result = 0\n            while (m > 0) {\n                result++\n                m = m shr 1\n            }\n            return result\n        }\n\n        private fun backwardLook(value: SignatureNode, numOfSteps: Int, originLevel: Int,\n                                 backEdges: Map<SignatureNode, Map<ContractTransition, SignatureNode>>): Collection<String> {\n            var nodesOnCurrentLevel = HashSet<SignatureNode>()\n            nodesOnCurrentLevel.add(value)\n            var currentStep = numOfSteps;\n            while (currentStep >= 0) {\n                if (currentStep > 0 ) {\n                    val nodesOnPreviousLevel = HashSet<SignatureNode>()\n                    for (node in nodesOnCurrentLevel) {\n                        for ((_, pred) in backEdges[node]!!) {\n                            nodesOnPreviousLevel.add(pred)\n                        }\n                    }\n                    nodesOnCurrentLevel = nodesOnPreviousLevel\n                } else {\n                    val result = HashSet<String>()\n                    for (node in nodesOnCurrentLevel) {\n                        for ((transition, _) in backEdges[node]!!) {\n                            if (transition is TypedContractTransition) {\n                                result.add(transition.type)\n                            } else if (transition is ReferenceContractTransition) {\n                                val curLevel = originLevel - numOfSteps\n                                val curNumOfSteps = curLevel - getHighestSetBit(transition.mask)\n                                val res = backwardLook(node, curNumOfSteps, curLevel, backEdges)\n                                result.addAll(res)\n                            } else\n                                throw IllegalArgumentException(\"Cannot reach\")\n\n                        }\n                    }\n                    return result\n                }\n                currentStep--;\n            }\n            throw IllegalArgumentException(\"Cannot reach\")\n        }\n    }\n}\n\ninterface SignatureNode {\n    val transitions: Map<ContractTransition, SignatureNode>\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/SignatureInfo.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\ninterface SignatureInfo {\n    val methodInfo: MethodInfo\n    val contract: SignatureContract\n\n    data class Impl(override val methodInfo: MethodInfo, override val contract: SignatureContract) : SignatureInfo\n}\n\nfun SignatureInfo(methodInfo: MethodInfo, contract: SignatureContract) = SignatureInfo.Impl(methodInfo, contract)\n\nfun SignatureInfo(copy: SignatureInfo) = with(copy) { SignatureInfo.Impl(MethodInfo(methodInfo), contract) }"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/contractTransition/ContractTransition.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.contractTransition;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\nimport java.util.Set;\n\npublic interface ContractTransition {\n    /**\n     * Return literal type set of this transition. This method respects reference transitions\n     * which types depend on some previous passed values.\n     *\n     * @param readTypes previously read literal types. Set represents possible type unions\n     * @return computed literal type set for this transition\n     */\n    @NotNull\n    Set<String> getValue(@NotNull List<Set<String>> readTypes);\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/contractTransition/ReferenceContractTransition.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.contractTransition;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ReferenceContractTransition implements ContractTransition {\n\n    private final int myMask;\n\n    public ReferenceContractTransition(int mask) {\n        myMask = mask;\n    }\n\n    @NotNull\n    @Override\n    public Set<String> getValue(@NotNull List<Set<String>> readTypes) {\n        int tmpMask = myMask;\n        int cnt = 0;\n\n        Set<String> ans = null;\n\n        while (tmpMask > 0) {\n            if (tmpMask % 2 == 1) {\n                if (ans == null) {\n                    ans = new HashSet<>(readTypes.get(cnt));\n                } else {\n                    ans.retainAll(readTypes.get(cnt));\n                }\n            }\n\n            tmpMask /= 2;\n            cnt++;\n        }\n\n        return ans;\n    }\n\n    public int getMask() {\n        return myMask;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        ReferenceContractTransition that = (ReferenceContractTransition) o;\n\n        return myMask == that.myMask;\n    }\n\n    @Override\n    public int hashCode() {\n        return myMask;\n    }\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/contractTransition/TransitionHelper.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.contractTransition;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\npublic class TransitionHelper {\n    private TransitionHelper() {\n    }\n\n    @NotNull\n    public static ContractTransition calculateTransition(@NotNull List<String> argTypes, int argIndex, @NotNull String type) {\n        final int mask = getNewMask(argTypes, argIndex, type);\n\n        if (mask > 0)\n            return new ReferenceContractTransition(mask);\n        else\n            return new TypedContractTransition(type);\n    }\n\n    private static int getNewMask(@NotNull List<String> argsTypes, int argIndex, @NotNull String type) {\n        int tempMask = 0;\n\n        for (int i = argIndex - 1; i >= 0; i--) {\n            tempMask <<= 1;\n\n            if (argsTypes.get(i).equals(type)) {\n                tempMask |= 1;\n            }\n        }\n\n        return tempMask;\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/contractTransition/TypedContractTransition.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.contractTransition;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\npublic class TypedContractTransition implements ContractTransition {\n\n    @NotNull\n    private final String myType;\n\n    public TypedContractTransition(@NotNull String type) {\n        this.myType = type;\n    }\n\n    @NotNull\n    @Override\n    public Set<String> getValue(@NotNull List<Set<String>> readTypes) {\n        return Collections.singleton(myType);\n    }\n\n    @NotNull\n    public String getType() {\n        return myType;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TypedContractTransition that = (TypedContractTransition) o;\n\n        return myType.equals(that.myType);\n    }\n\n    @Override\n    public int hashCode() {\n        return myType.hashCode();\n    }\n}"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/serialization/MethodInfoSerialization.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.serialization\n\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport java.io.DataInput\nimport java.io.DataOutput\nimport java.io.IOException\n\nfun MethodInfo.serialize(stream: DataOutput) {\n    classInfo.serialize(stream)\n    stream.writeUTF(name)\n    stream.writeByte(visibility.ordinal)\n    stream.writeBoolean(location != null)\n    location?.serialize(stream)\n}\n\nfun MethodInfo(stream: DataInput): MethodInfo {\n    val classInfo = ClassInfo(stream)\n    val name = stream.readUTF()\n    val visibility = RVisibility.values()[stream.readByte().toInt()]\n    val isLocationPresent = stream.readBoolean()\n    val location = if (isLocationPresent) Location(stream) else null\n\n    return MethodInfo.Impl(classInfo, name, visibility, location)\n}\n\nfun ClassInfo.serialize(stream: DataOutput) {\n    stream.writeUTF(classFQN)\n    gemInfo.serialize(stream)\n}\n\nfun ClassInfo(stream: DataInput): ClassInfo {\n    val classFQN = stream.readUTF()\n    val gemInfo = GemInfo(stream)\n\n    return ClassInfo(gemInfo, classFQN)\n}\n\nfun GemInfo?.serialize(stream: DataOutput) {\n    (this ?: GemInfo.NONE).let {\n        stream.writeUTF(it.name)\n        stream.writeUTF(it.version)\n    }\n}\n\nfun GemInfo(stream: DataInput): GemInfo? {\n    val name = stream.readUTF()\n    val version = stream.readUTF()\n    return GemInfoOrNull(name, version)\n}\n\nfun Location.serialize(stream: DataOutput) {\n    stream.writeUTF(path)\n    stream.writeInt(lineno)\n}\n\nfun Location(stream: DataInput): Location {\n    val path = stream.readUTF()\n    val lineno = stream.readInt()\n\n    return Location(path, lineno)\n}\n\nobject SignatureInfoSerialization {\n\n    private val PROTOCOL_VERSION = 1\n\n    fun serialize(signatureInfos: List<SignatureInfo>, stream: DataOutput) {\n        writeProtocolVersion(stream)\n\n        val (classInfo2Id, gemInfo2Id) = collectClassInfoAndGemInfo(signatureInfos)\n        serializeGemInfos(gemInfo2Id, stream)\n        serializeClassInfos(stream, classInfo2Id, gemInfo2Id)\n        serializeSignatureInfos(stream, signatureInfos, classInfo2Id)\n    }\n\n    fun deserialize(stream: DataInput): List<SignatureInfo> {\n        checkProtocolVersion(stream)\n\n        val id2GemInfo = deserializeGemInfo(stream)\n        val id2ClassInfo = deserializeClassInfo(stream, id2GemInfo)\n        return deserializeSignatureInfos(stream, id2ClassInfo)\n    }\n\n    private fun writeProtocolVersion(stream: DataOutput) {\n        stream.writeInt(PROTOCOL_VERSION)\n    }\n\n\n    private fun checkProtocolVersion(stream: DataInput) {\n        val version = stream.readInt()\n        if (version != PROTOCOL_VERSION) {\n            throw IOException(\"Cannot deserialize SignatureInfos: protocol version mismatch. Expected:\" +\n                    \" $PROTOCOL_VERSION but got: $version\")\n        }\n    }\n\n    private fun collectClassInfoAndGemInfo(signatureInfos: List<SignatureInfo>) :\n            Pair<LinkedHashMap<ClassInfo, Int>, LinkedHashMap<GemInfo, Int>>{\n        val gemInfo2Id = LinkedHashMap<GemInfo, Int>()\n        val classInfo2Id = LinkedHashMap<ClassInfo, Int>()\n        signatureInfos.forEach {\n            val classInfo = it.methodInfo.classInfo\n            val gemInfo = classInfo.gemInfo\n            classInfo2Id.putIfAbsent(classInfo, classInfo2Id.size)\n            gemInfo?.let {\n                gemInfo2Id.putIfAbsent(gemInfo, gemInfo2Id.size)\n            }\n        }\n        return Pair(classInfo2Id, gemInfo2Id)\n    }\n\n    private fun serializeGemInfos(gemInfo2Id: LinkedHashMap<GemInfo, Int>, stream: DataOutput) {\n        stream.writeInt(gemInfo2Id.size)\n        var iter = 0\n        gemInfo2Id.forEach {\n            assert(iter++ == it.value)\n            it.key.serialize(stream)\n        }\n    }\n\n    private fun deserializeGemInfo(stream: DataInput): LinkedHashMap<Int, GemInfo> {\n        val id2GemInfo = LinkedHashMap<Int, GemInfo>()\n        val gemInfoSize = stream.readInt()\n        for (i in 1..gemInfoSize) {\n            val gemInfo = GemInfo(stream)!!\n            id2GemInfo.put(i - 1, gemInfo)\n        }\n        id2GemInfo.put(-1, GemInfo.NONE)\n        return id2GemInfo\n    }\n\n    private fun serializeClassInfos(stream: DataOutput, classInfo2Id: LinkedHashMap<ClassInfo, Int>, gemInfo2Id: LinkedHashMap<GemInfo, Int>) {\n        gemInfo2Id.put(GemInfo.NONE, -1)\n        var iter = 0\n        stream.writeInt(classInfo2Id.size)\n        classInfo2Id.forEach {\n            assert(iter++ == it.value)\n            stream.writeUTF(it.key.classFQN)\n            stream.writeInt(gemInfo2Id.getValue(it.key.gemInfo ?: GemInfo.NONE))\n        }\n    }\n\n    private fun deserializeClassInfo(stream: DataInput,\n                                     id2GemInfo: LinkedHashMap<Int, GemInfo>): LinkedHashMap<Int, ClassInfo> {\n        val id2ClassInfo = LinkedHashMap<Int, ClassInfo>()\n        val classInfoSize = stream.readInt()\n        for (i in 1..classInfoSize) {\n            val fqn = stream.readUTF()\n            val gemInfo = id2GemInfo.getValue(stream.readInt())\n            id2ClassInfo.put(i - 1, ClassInfo(gemInfo, fqn))\n        }\n        return id2ClassInfo\n    }\n\n    private fun serializeSignatureInfos(stream: DataOutput, signatureInfos: List<SignatureInfo>, classInfo2Id: LinkedHashMap<ClassInfo, Int>) {\n        stream.writeInt(signatureInfos.size)\n        signatureInfos.forEach {\n            val methodInfo = it.methodInfo\n            stream.writeUTF(methodInfo.name)\n            stream.writeByte(methodInfo.visibility.ordinal)\n            stream.writeBoolean(methodInfo.location != null)\n            methodInfo.location?.serialize(stream)\n            stream.writeInt(classInfo2Id.getValue(methodInfo.classInfo))\n            it.contract.serialize(stream)\n        }\n    }\n\n    private fun deserializeSignatureInfos(stream: DataInput,\n                                          id2ClassInfo: LinkedHashMap<Int, ClassInfo>) : List<SignatureInfo> {\n        val result = ArrayList<SignatureInfo>()\n        val signatureInfoSize = stream.readInt()\n        for (i in 1..signatureInfoSize) {\n            val name = stream.readUTF()\n            val visibility = RVisibility.values()[stream.readByte().toInt()]\n            val isLocationPresent = stream.readBoolean()\n            val location = if (isLocationPresent) Location(stream) else null\n            val classInfo = id2ClassInfo.getValue(stream.readInt())\n            val methodInfo = MethodInfo.Impl(classInfo, name, visibility, location)\n            val contract = SignatureContract(stream)\n            result.add(SignatureInfo(methodInfo, contract))\n        }\n        return result\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/serialization/RmcDirectory.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.serialization\n\nimport org.jetbrains.ruby.codeInsight.types.signature.GemInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.SignatureInfo\nimport java.io.*\nimport java.util.zip.GZIPInputStream\nimport java.util.zip.GZIPOutputStream\n\ninterface RmcDirectory {\n    fun save(gemInfo: GemInfo, signatures: List<SignatureInfo>)\n\n    fun listGems() : List<GemInfo>\n\n    fun load(gemInfo: GemInfo): List<SignatureInfo>\n\n}\n\nclass RmcDirectoryImpl(private val directory: File) : RmcDirectory {\n    init {\n        if (!directory.exists() || !directory.isDirectory) {\n            throw IOException(\"Existing directory excepted\")\n        }\n    }\n\n    override fun load(gemInfo: GemInfo): List<SignatureInfo> {\n        val inputFile = File(directory, gemInfo2Filename(gemInfo))\n        FileInputStream(inputFile).use {\n            GZIPInputStream(it).use {\n                DataInputStream(it).use {\n                    return SignatureInfoSerialization.deserialize(it)\n                }\n            }\n        }\n    }\n\n    override fun save(gemInfo: GemInfo, signatures: List<SignatureInfo>) {\n        val outputFile = File(directory, gemInfo2Filename(gemInfo))\n        FileOutputStream(outputFile).use {\n            GZIPOutputStream(it).use {\n                DataOutputStream(it).use {\n                    SignatureInfoSerialization.serialize(signatures, it)\n                }\n            }\n        }\n    }\n\n    override fun listGems(): List<GemInfo> = directory.listFiles().mapNotNull { file2GemInfo(it) }\n\n    private fun gemInfo2Filename(gemInfo: GemInfo) = \"${gemInfo.name}-${gemInfo.version}.rmc\"\n\n    private fun file2GemInfo(file: File): GemInfo? {\n        if (file.extension != \"rmc\") {\n            return null\n        }\n        val name = file.nameWithoutExtension.substringBeforeLast('-')\n        val version = file.nameWithoutExtension.substringAfterLast('-')\n        if (name == \"\" || version == \"\") {\n            return null\n        }\n        return GemInfo(name, version)\n    }\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/serialization/SignatureContractSerialization.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.serialization\n\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ContractTransition\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.ReferenceContractTransition\nimport org.jetbrains.ruby.codeInsight.types.signature.contractTransition.TypedContractTransition\nimport java.io.DataInput\nimport java.io.DataOutput\nimport java.util.*\nimport kotlin.collections.ArrayList\nimport kotlin.collections.HashMap\n\nfun ContractTransition.serialize(stream: DataOutput) {\n    stream.writeBoolean(this is ReferenceContractTransition)\n    when (this) {\n        is ReferenceContractTransition -> stream.writeInt(mask)\n        is TypedContractTransition -> stream.writeUTF(type)\n        else -> throw IllegalStateException(\"ContractTransition should be sealed in these classes\")\n    }\n}\n\nfun ContractTransition(stream: DataInput): ContractTransition {\n    val type = stream.readBoolean()\n    return when (type) {\n        true -> ReferenceContractTransition(stream.readInt())\n        false -> TypedContractTransition(stream.readUTF())\n    }\n}\n\nfun ParameterInfo.serialize(stream: DataOutput) {\n    stream.writeUTF(name)\n    stream.writeByte(modifier.ordinal)\n}\n\nfun ParameterInfo(stream: DataInput): ParameterInfo {\n    return ParameterInfo(stream.readUTF(), ParameterInfo.Type.values()[stream.readByte().toInt()])\n}\n\nfun SignatureContract.serialize(stream: DataOutput) {\n    stream.writeInt(argsInfo.size)\n    argsInfo.forEach { it.serialize(stream) }\n\n    stream.writeInt(nodeCount)\n\n    val visited = HashMap<SignatureNode, Int>()\n    val q = ArrayDeque<SignatureNode>()\n\n    visited[startNode] = 0\n    q.push(startNode)\n\n    while (q.isNotEmpty()) {\n        val v = q.poll()\n        for (it in v.transitions.values) {\n            if (!visited.containsKey(it)) {\n                visited[it] = visited.size\n                q.add(it)\n            }\n        }\n\n        stream.writeInt(v.transitions.size)\n        v.transitions.forEach { transition, u ->\n            stream.writeInt(visited[u]!!)\n            transition.serialize(stream)\n        }\n    }\n}\n\nfun SignatureContract(stream: DataInput): SignatureContract {\n    val argsSize = stream.readInt()\n    val argsInfo = List(argsSize) { ParameterInfo(stream) }\n\n    val nodesSize = stream.readInt()\n\n    val nodes = List(nodesSize) { RSignatureContractNode() }\n\n    val distance = IntArray(nodesSize, { 0 })\n\n    repeat(nodesSize) { currentNodeIndex ->\n        val transitionsN = stream.readInt()\n\n        repeat(transitionsN) {\n            val toIndex = stream.readInt()\n            distance[toIndex] = distance[currentNodeIndex] + 1\n            val transition = ContractTransition(stream)\n            // todo replace with constructor (iterate from the end)\n            nodes[currentNodeIndex].addLink(transition, nodes[toIndex])\n        }\n    }\n\n    val levels = List(argsSize + 2) { ArrayList<RSignatureContractNode>() }\n    nodes.indices.forEach {\n        levels[distance[it]].add(nodes[it])\n    }\n\n    return RSignatureContract(argsInfo, nodes.first(), nodes.last(), levels)\n\n}\n"
  },
  {
    "path": "ruby-call-signature/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/serialization/TestSerialization.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.serialization\n\nimport java.io.DataInput\nimport java.io.DataOutput\nimport java.util.*\n\nclass StringDataOutput : DataOutput {\n    val result = StringBuilder()\n\n    private var wasNewline = true\n\n    fun newline() {\n        result.append(\"\\n\")\n        wasNewline = true\n    }\n\n    private fun writeSpace() {\n        if (!wasNewline) {\n            result.append(' ')\n        }\n        wasNewline = false\n    }\n\n    override fun writeShort(v: Int): Unit = TODO(\"not implemented\")\n\n    override fun writeLong(v: Long): Unit = TODO(\"not implemented\")\n\n    override fun writeDouble(v: Double): Unit = TODO(\"not implemented\")\n\n    override fun writeBytes(s: String?): Unit = TODO(\"not implemented\")\n\n    override fun writeByte(v: Int) {\n        writeSpace()\n        result.append(v)\n    }\n\n    override fun writeFloat(v: Float): Unit = TODO(\"not implemented\")\n\n    override fun write(b: Int): Unit = TODO(\"not implemented\")\n\n    override fun write(b: ByteArray?): Unit = TODO(\"not implemented\")\n\n    override fun write(b: ByteArray?, off: Int, len: Int): Unit = TODO(\"not implemented\")\n\n    override fun writeChars(s: String?): Unit = TODO(\"not implemented\")\n\n    override fun writeChar(v: Int): Unit = TODO(\"not implemented\")\n\n    override fun writeBoolean(v: Boolean) {\n        writeSpace()\n        result.append(if (v) '1' else '0')\n    }\n\n    override fun writeUTF(s: String?) {\n        writeSpace()\n        result.append(s)\n    }\n\n    override fun writeInt(v: Int) {\n        writeSpace()\n        result.append(v)\n    }\n}\n\nclass StringDataInput(s: String) : DataInput {\n    private val scanner = Scanner(s)\n\n    override fun readFully(b: ByteArray?): Unit = TODO(\"not implemented\")\n\n    override fun readFully(b: ByteArray?, off: Int, len: Int): Unit = TODO(\"not implemented\")\n\n    override fun readInt(): Int = scanner.nextInt()\n\n    override fun readUnsignedShort(): Int = TODO(\"not implemented\")\n\n    override fun readUnsignedByte(): Int = TODO(\"not implemented\")\n\n    override fun readUTF(): String = scanner.next()\n\n    override fun readChar(): Char = TODO(\"not implemented\")\n\n    override fun readLine(): String = TODO(\"not implemented\")\n\n    override fun readByte(): Byte = scanner.nextByte()\n\n    override fun readFloat(): Float = TODO(\"not implemented\")\n\n    override fun skipBytes(n: Int): Int = TODO(\"not implemented\")\n\n    override fun readLong(): Long = TODO(\"not implemented\")\n\n    override fun readDouble(): Double = TODO(\"not implemented\")\n\n    override fun readBoolean(): Boolean = (scanner.nextInt() == 1)\n\n    override fun readShort(): Short = TODO(\"not implemented\")\n}"
  },
  {
    "path": "ruby-call-signature/src/test/java/org/jetbrains/ruby/codeInsight/types/signature/GemInfoFromPathTest.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nimport junit.framework.TestCase\nimport org.junit.Test\n\nclass GemInfoFromPathTest : TestCase() {\n    private fun doTest(path: String, gemName: String, gemVersion: String) {\n        assertEquals(GemInfoOrNull(gemName, gemVersion), gemInfoFromFilePathOrNull(path))\n    }\n\n    @Test\n    fun testToplevel() {\n        doTest(\"/home/valich/foo.rb\", \"\", \"\")\n    }\n\n    @Test\n    fun testRubyBundled() {\n        doTest(\"/Users/valich/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/mkmf.rb\", \"ruby\", \"2.3.3\")\n    }\n\n    @Test\n    fun testRakeRVM() {\n        doTest(\"/Users/valich/.rvm/rubies/ruby-2.3.3/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake.rb\",\n                \"rake\", \"10.4.2\")\n    }\n\n    @Test\n    fun testGemNameWithDashes() {\n        doTest(\"/Users/valich/.rvm/gems/ruby-2.3.3/gems/debase-ruby_core_source-0.9.9/lib/debase/ruby_core_source.rb\",\n                \"debase-ruby_core_source\", \"0.9.9\")\n    }\n\n    @Test\n    fun testMacPreinstalledGem() {\n        doTest(\"/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/gems/2.3.0/gems/sqlite3-1.3.11/lib/sqlite3.rb\",\n                \"sqlite3\", \"1.3.11\")\n    }\n\n    @Test\n    fun testMacSystemGem() {\n        doTest(\"/Users/valich/.gem/ruby/2.3.0/gems/activerecord-5.0.1/lib/active_record.rb\",\n                \"activerecord\", \"5.0.1\")\n    }\n}"
  },
  {
    "path": "ruby-call-signature/src/test/java/org/jetbrains/ruby/codeInsight/types/signature/SignatureContractMergeTest.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nimport org.junit.Test\n\nclass SignatureContractMergeTest : SignatureContractTestBase() {\n\n    @Test\n    fun testSimpleMerge() {\n        val contract = generateSimpleContract()\n\n        val testArgs1 = listOf(\"Int1\", \"Int2\", \"Int3\")\n        val testArgs2 = listOf(\"String1\", \"Int2\", \"Int3\")\n\n        val testTuple1 = generateRTuple(testArgs1, \"String4\")\n        val testTuple2 = generateRTuple(testArgs2, \"String4\")\n\n        assertTrue(SignatureContract.accept(contract, testTuple1))\n        assertFalse(SignatureContract.accept(contract, testTuple2))\n\n        checkSerialization(contract, MergeTestData.testSimpleMerge)\n    }\n\n    @Test\n    fun testComplicatedMerge() {\n        val testArgs1 = listOf(\"a1\", \"b2\", \"a3\", \"d4\")\n        val testArgs2 = listOf(\"a1\", \"c2\", \"b3\", \"d4\")\n        val testTuple1 = generateRTuple(testArgs1, \"a5\")\n        val testTuple2 = generateRTuple(testArgs2, \"a5\")\n\n        val contract = generateComplicatedContract()\n\n        assertFalse(SignatureContract.accept(contract, testTuple1))\n        assertTrue(SignatureContract.accept(contract, testTuple2))\n\n        checkSerialization(contract, MergeTestData.testComplicatedMerge)\n    }\n\n    @Test\n    fun testMultipleReturnTypeMerge() {\n        val contract = generateMultipleReturnTypeContract()\n        checkSerialization(contract, MergeTestData.testMultipleReturnTypeMerge)\n    }\n\n    @Test\n    fun testAdd() {\n        val testArgs1 = listOf(\"String1\", \"Date2\", \"String3\")\n        val testTuple1 = generateRTuple(testArgs1, \"String4\")\n\n        val contract = generateAddContract()\n        assertTrue(SignatureContract.accept(contract, testTuple1))\n\n        checkSerialization(contract, MergeTestData.testAddResult)\n    }\n}\n\n\n"
  },
  {
    "path": "ruby-call-signature/src/test/java/org/jetbrains/ruby/codeInsight/types/signature/SignatureContractSerializationTest.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.*\nimport org.junit.Test\nimport java.io.ByteArrayInputStream\nimport java.io.ByteArrayOutputStream\nimport java.io.DataInputStream\nimport java.io.DataOutputStream\nimport java.util.zip.GZIPInputStream\nimport java.util.zip.GZIPOutputStream\n\nclass SignatureContractSerializationTest : SignatureContractTestBase() {\n\n    private fun checkSignaturesSerialization(signatures: List<SignatureInfo.Impl>,\n                                             newSignatures: List<SignatureInfo>, contractsTestData: List<String>) {\n        assertTrue(signatures.size == newSignatures.size)\n        for (i in 0 until newSignatures.size) {\n            assertTrue(signatures[i].methodInfo == newSignatures[i].methodInfo)\n            checkSerialization(signatures[i].contract, contractsTestData[i % 4])\n        }\n    }\n\n    private fun generateSignatures(): Pair<List<String>, List<SignatureInfo.Impl>> {\n        val gems = listOf(\n                GemInfo(\"gem\", \"1.2.3\"),\n                GemInfo(\"anothergem\", \"3.4.5\"),\n                GemInfo(\"supergem\", \"0.99\")\n        )\n        val classNames = listOf(\"A::B::C\",\n                \"B::C::D\",\n                \"D::E::F\")\n\n        val classes = gems.map { gem -> classNames.map { ClassInfo(gem, it) } }.flatten()\n        val methodNames = listOf(\"foo\", \"bar\", \"baz\", \"foobar\")\n        val methods = classes.map { clazz -> methodNames.map { MethodInfo(clazz, it, RVisibility.PUBLIC) } }.flatten()\n        val contracts = listOf(generateSimpleContract(), generateComplicatedContract(),\n                generateMultipleReturnTypeContract(), generateAddContract())\n        val contractsTestData = listOf(MergeTestData.testSimpleMerge, MergeTestData.testComplicatedMerge,\n                MergeTestData.testMultipleReturnTypeMerge, MergeTestData.testAddResult)\n        assertTrue(contracts.size == contractsTestData.size)\n\n        var idx = 0\n        val signatures = methods.map { SignatureInfo(it, contracts[idx++ % contracts.size]) }\n        return Pair(contractsTestData, signatures)\n    }\n\n\n    private fun doTest(contract: String) {\n        val normalizedInput = contract.trim().replace('\\n', ' ')\n        val signatureContract = SignatureContract(StringDataInput(normalizedInput))\n        val serialized = StringDataOutput().let {\n            signatureContract.serialize(it)\n            it.result.toString()\n        }\n\n        assertEquals(normalizedInput, serialized)\n    }\n\n    fun testSimple() {\n        doTest(SignatureTestData.simpleContract)\n    }\n\n    @Test\n    fun testSerializationList() {\n        val (contractsTestData, signatures) = generateSignatures()\n\n        val dataOutput = StringDataOutput()\n        SignatureInfoSerialization.serialize(signatures, dataOutput)\n        val newSignatures = SignatureInfoSerialization.deserialize(StringDataInput(dataOutput.result.toString()))\n\n        checkSignaturesSerialization(signatures, newSignatures, contractsTestData)\n    }\n\n    @Test\n    fun testBinarySerialization() {\n        val (contractsTestData, signatures) = generateSignatures()\n\n        val outputStream = ByteArrayOutputStream()\n        GZIPOutputStream(outputStream).use {\n            DataOutputStream(outputStream).use {\n                SignatureInfoSerialization.serialize(signatures, it)\n            }\n        }\n\n        val inputStream = ByteArrayInputStream(outputStream.toByteArray())\n        GZIPInputStream(inputStream).use {\n            DataInputStream(inputStream).use {\n                val newSignatures = SignatureInfoSerialization.deserialize(it)\n                checkSignaturesSerialization(signatures, newSignatures, contractsTestData)\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "ruby-call-signature/src/test/java/org/jetbrains/ruby/codeInsight/types/signature/SignatureContractTestBase.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature\n\nimport junit.framework.TestCase\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.StringDataOutput\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.serialize\n\nabstract class SignatureContractTestBase : TestCase() {\n\n    protected fun checkSerialization(rContract: SignatureContract, testData: String) {\n        val serialized = StringDataOutput().let {\n            rContract.serialize(it)\n            it.result.toString()\n        }\n\n        val testDataClean = testData.trim().replace('\\n', ' ')\n\n        assertEquals(serialized, testDataClean)\n    }\n\n    protected fun generateComplicatedContract() : RSignatureContract {\n        val args1 = listOf(\"a1\", \"c2\", \"a3\", \"a4\")\n        val args2 = listOf(\"a1\", \"b2\", \"a3\", \"a4\")\n        val args3 = listOf(\"a1\", \"c2\", \"b3\", \"a4\")\n        val args4 = listOf(\"a1\", \"b2\", \"b3\", \"a4\")\n\n        val args5 = listOf(\"a1\", \"c2\", \"b3\", \"d4\")\n        val args6 = listOf(\"a1\", \"b2\", \"b3\", \"d4\")\n\n        val tuple1 = generateRTuple(args1, \"e5\")\n        val tuple2 = generateRTuple(args2, \"e5\")\n        val tuple3 = generateRTuple(args3, \"e5\")\n        val tuple4 = generateRTuple(args4, \"e5\")\n\n\n        val tuple5 = generateRTuple(args5, \"a5\")\n        val tuple6 = generateRTuple(args6, \"a5\")\n\n        val contract1 = RSignatureContract(tuple1)\n        contract1.addRTuple(tuple2)\n        contract1.addRTuple(tuple3)\n        contract1.addRTuple(tuple4)\n\n        contract1.minimize()\n\n        val contract2 = RSignatureContract(tuple5)\n        contract2.addRTuple(tuple6)\n        contract2.minimize()\n\n        contract1.mergeWith(contract2)\n\n        return contract1\n    }\n\n    protected fun generateSimpleContract() : RSignatureContract {\n        val args1 = listOf(\"String1\", \"String2\", \"String3\")\n        val args2 = listOf(\"Int1\", \"String2\", \"String3\")\n        val args3 = listOf(\"String1\", \"Int2\", \"String3\")\n        val args4 = listOf(\"Int1\", \"Int2\", \"String3\")\n\n        val args5 = listOf(\"Int1\", \"Int2\", \"Int3\")\n\n\n        val tuple1 = generateRTuple(args1, \"String4\")\n        val tuple2 = generateRTuple(args2, \"String4\")\n        val tuple3 = generateRTuple(args3, \"String4\")\n        val tuple4 = generateRTuple(args4, \"String4\")\n\n        val tuple5 = generateRTuple(args5, \"String4\")\n\n        val contract1 = RSignatureContract(tuple1)\n        contract1.addRTuple(tuple2)\n        contract1.addRTuple(tuple3)\n        contract1.addRTuple(tuple4)\n\n        contract1.minimize()\n\n        val contract2 = RSignatureContract(tuple5)\n\n        contract1.mergeWith(contract2)\n\n        return contract1\n    }\n\n\n    protected fun generateMultipleReturnTypeContract(): RSignatureContract {\n        val args1 = listOf(\"a1\")\n        val args2 = listOf(\"a1\")\n\n        val args3 = listOf(\"a1\")\n\n        val tuple1 = generateRTuple(args1, \"b2\")\n        val tuple2 = generateRTuple(args2, \"c2\")\n\n        val tuple3 = generateRTuple(args3, \"d2\")\n\n        val contract1 = RSignatureContract(tuple1)\n        contract1.addRTuple(tuple2)\n\n        contract1.minimize()\n\n        val contract2 = RSignatureContract(tuple3)\n\n        contract1.mergeWith(contract2)\n        return contract1\n    }\n\n    protected fun generateAddContract(): RSignatureContract {\n        val testArgs1 = listOf(\"String1\", \"Date2\", \"String3\")\n        val testTuple1 = generateRTuple(testArgs1, \"String4\")\n        val args1 = listOf(\"String1\", \"String2\", \"String3\")\n        val args2 = listOf(\"String1\", \"Int2\", \"String3\")\n\n        val tuple1 = generateRTuple(args1, \"String4\")\n        val tuple2 = generateRTuple(args2, \"String4\")\n\n        val contract1 = RSignatureContract(tuple1)\n        contract1.addRTuple(tuple2)\n\n        contract1.minimize()\n\n        val contract2 = RSignatureContract(testTuple1)\n\n        contract1.mergeWith(contract2)\n        return contract1\n    }\n\n    protected fun generateRTuple(args: List<String>, returnType: String): RTuple {\n        val gemInfo = GemInfo.Impl(\"test_gem\", \"1.2.3\")\n        val classInfo = ClassInfo.Impl(gemInfo, \"TEST1::Fqn\")\n        val location = Location(\"test1test1\", 11)\n        val methodInfo = MethodInfo.Impl(classInfo, \"met1\", RVisibility.PUBLIC, location)\n\n        val params = args.indices.map { ParameterInfo(\"a\" + it, ParameterInfo.Type.REQ) }\n\n        return RTuple(methodInfo, params, args, returnType)\n    }\n\n    object SignatureTestData {\n        val simpleContract = \"\"\"\n1 arg 0\n4\n3\n1 0 a\n2 0 b\n2 0 c\n1\n3 0 d\n1\n3 1 0\n0\n            \"\"\"\n\n        val trivialContract = \"\"\"\n0\n2\n1\n1 0 a\n0\n\"\"\"\n\n    }\n\n\n\n    object MergeTestData {\n        val testAddResult = \"\"\"\n3\na0 0\na1 0\na2 0\n5\n1\n1 0 String1\n3\n2 0 Int2\n2 0 Date2\n2 0 String2\n1\n3 0 String3\n1\n4 0 String4\n0\n            \"\"\"\n        val testSimpleMerge = \"\"\"\n3\na0 0\na1 0\na2 0\n7\n2\n1 0 Int1\n2 0 String1\n2\n3 0 Int2\n4 0 String2\n2\n4 0 Int2\n4 0 String2\n2\n5 0 Int3\n5 0 String3\n1\n5 0 String3\n1\n6 0 String4\n0\n            \"\"\"\n\n        val testComplicatedMerge = \"\"\"\n4\na0 0\na1 0\na2 0\na3 0\n8\n1\n1 0 a1\n2\n2 0 b2\n2 0 c2\n2\n3 0 b3\n4 0 a3\n2\n5 0 d4\n6 0 a4\n1\n6 0 a4\n1\n7 0 a5\n1\n7 0 e5\n0\n            \"\"\"\n        val testMultipleReturnTypeMerge = \"\"\"\n1\na0 0\n3\n1\n1 0 a1\n3\n2 0 b2\n2 0 d2\n2 0 c2\n0            \"\"\"\n    }\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "include 'ruby-call-signature', 'storage-server-api', 'lambda-update-handler', 'lambda-put-handler'\ninclude 'contract-creator'\ninclude 'ide-plugin'\ninclude 'signature-viewer'\ninclude 'state-tracker'\ninclude 'common'\n\n"
  },
  {
    "path": "signature-viewer/build.gradle",
    "content": "version 'unspecified'\n\napply plugin: 'java'\n\nsourceCompatibility = 1.8\n\nrepositories {\n    mavenCentral()\n}\n\n\ndependencies {\n    compile project(':ruby-call-signature')\n    compile project(':storage-server-api')\n\n//    compile 'com.h2database:h2:1.4.193'\n    compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'\n}\n\ntask runViewer(type: JavaExec) {\n    classpath sourceSets.main.runtimeClasspath\n    main = 'org.jetbrains.ruby.runtime.signature.SignatureViewerKt'\n}\n\ntask runExport(type: JavaExec) {\n    if (project.hasProperty(\"outputDir\")) {\n        args = [\"$outputDir\"]\n    } else {\n        args = [\"rmcOutput\"]\n    }\n    classpath sourceSets.main.runtimeClasspath\n    main = 'org.jetbrains.ruby.runtime.signature.SignatureExportKt'\n}\n\ntask runImport(type: JavaExec) {\n    if (project.hasProperty(\"inputDir\")) {\n        args = [\"$inputDir\"]\n    } else {\n        args = [\"rmcInput\"]\n    }\n    classpath sourceSets.main.runtimeClasspath\n    main = 'org.jetbrains.ruby.runtime.signature.SignatureImportKt'\n}\n\n\nsourceSets {\n    main.java.srcDirs = ['src']\n}"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/DBViewer.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoRow\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\n\n/**\n * Just prints content of [CallInfoTable]\n */\nfun main(args: Array<String>) {\n    val dpPath = parseDBViewerCommandLineArgs(args)\n    DatabaseProvider.connectToDB(dpPath)\n\n    transaction {\n        val table = CallInfoRow.all().map { it.copy() }\n        table.forEach {\n            println(\"\" +\n                    (it.methodInfo.classInfo.gemInfo?.name ?: \"No gem\") + \" \" +\n                    (it.methodInfo.classInfo.gemInfo?.version ?: \"No version\") + \" \" +\n                    it.methodInfo.location?.path + \" \" +\n                    it.methodInfo.location?.lineno + \" \" +\n                    it.methodInfo.visibility + \" \" +\n                    it.methodInfo.classInfo.classFQN + \" \" +\n                    it.methodInfo.name + \" \" +\n                    \"args:${it.unnamedArgumentsTypesJoinToRawString()} \" +\n                    \"return:${it.returnType}\")\n        }\n        println(\"Size: ${table.size}\")\n    }\n}\n\nfun parseDBViewerCommandLineArgs(args: Array<String>): String {\n    if (args.size != 1) {\n        println(\"Usage: <db-file-path>\")\n        System.exit(1)\n    }\n    return args.single()\n}\n"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/EraseLocation.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.exposed.sql.update\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.Location\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.MethodInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.MethodInfoTable\n\n/**\n * Erases location. This is needed because annotated [MethodInfo]s shouldn't contain any info related to how\n * machine of developer who annotated some lib is configured. But [Location] contains home dir,\n * .rvm or .rbenv folder, e.t.c so it's needed to be erased for annotated libs.\n */\nfun main(args: Array<String>) {\n    val dpPath = parseDBViewerCommandLineArgs(args)\n    DatabaseProvider.connectToDB(dpPath)\n\n    transaction {\n        // This is updateAll\n        MethodInfoTable.update {\n            it[MethodInfoTable.locationFile] = null\n        }\n    }\n}\n"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/SignatureExport.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.ruby.codeInsight.types.signature.SignatureInfo\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.RmcDirectoryImpl\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.StorageException\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport java.io.File\nimport java.nio.file.Paths\n\nconst val DB_NAME = \"ruby-type-inference-db\" + DatabaseProvider.H2_DB_FILE_EXTENSION\n\nfun main(arg : Array<String>) {\n    val outputDirPath = parseCommandLine(arg)\n    DatabaseProvider.connectToDB(Paths.get(outputDirPath, DB_NAME).toString())\n\n    val outputDir = File(outputDirPath)\n\n    if (!outputDir.exists()) {\n        outputDir.mkdirs()\n    }\n    val rmcDirectory = RmcDirectoryImpl(outputDir)\n\n\n    try {\n        for (gem in RSignatureProviderImpl.registeredGems) {\n            val signatureInfos = ArrayList<SignatureInfo>()\n            for (clazz in RSignatureProviderImpl.getRegisteredClasses(gem)) {\n                RSignatureProviderImpl.getRegisteredMethods(clazz).mapNotNullTo(signatureInfos) { RSignatureProviderImpl.getSignature(it) }\n            }\n            rmcDirectory.save(gem, signatureInfos)\n        }\n    } catch (e: StorageException) {\n        e.printStackTrace()\n    }\n\n}\n\nfun parseCommandLine(arg: Array<String>): String {\n    if (arg.size != 1) {\n        println(\"Usage: <path-to-output-dir>\")\n        System.exit(-1)\n    }\n    return arg[0]\n}\n"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/SignatureImport.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.RmcDirectoryImpl\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.StorageException\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport java.io.File\nimport java.nio.file.Paths\n\nfun main(arg : Array<String>) {\n    val outputDirPath = parseCommandLine(arg)\n    DatabaseProvider.connectToDB(Paths.get(outputDirPath, DB_NAME).toString())\n\n    val inputDirectory = File(outputDirPath)\n\n    if (!inputDirectory.exists()) {\n        inputDirectory.mkdirs()\n    }\n    val rmcDirectory = RmcDirectoryImpl(inputDirectory)\n\n    try {\n        rmcDirectory.listGems()\n                .map { rmcDirectory.load(it) }\n                .forEach { signatureInfos -> signatureInfos.forEach { RSignatureProviderImpl.putSignature(it) } }\n    } catch (e: StorageException) {\n        e.printStackTrace()\n    }\n\n}\n\n"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/SignatureViewer.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.ruby.codeInsight.types.signature.SignatureContract\nimport org.jetbrains.ruby.codeInsight.types.signature.SignatureInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.StorageException\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.RSignatureProviderImpl\nimport java.nio.file.Paths\n\nfun dumpSignatureInfo(signatureInfo: SignatureInfo) {\n    val methodInfo = signatureInfo.methodInfo\n    val classInfo = methodInfo.classInfo\n    val gemInfo = classInfo.gemInfo!!\n    println(gemInfo.name + \" \" + gemInfo.version + \" \" + classInfo.classFQN)\n    print(methodInfo.name + \" \")\n    methodInfo.location?.let { print( it.path + \" \" + it.lineno) }\n    SignatureContract.getAllReturnTypes(signatureInfo.contract).forEach { print(it + \", \") }\n    println()\n\n}\n\n\nfun main(args : Array<String>) {\n    val outputDirPath = parseCommandLine(args)\n    DatabaseProvider.connectToDB(Paths.get(outputDirPath, DB_NAME).toString())\n\n    val map = HashMap<String, MutableList<SignatureInfo>>()\n\n    try {\n        for (gem in RSignatureProviderImpl.registeredGems) {\n            for (clazz in RSignatureProviderImpl.getRegisteredClasses(gem)) {\n                for (method in RSignatureProviderImpl.getRegisteredMethods(clazz)) {\n                    val signatureInfo = RSignatureProviderImpl.getSignature(method)\n                    signatureInfo?.let<SignatureInfo?, Unit> {\n                        var list = map[method.name]\n                        if (list == null) {\n                            list = ArrayList()\n                            list.add(signatureInfo)\n                            map.put(method.name, list)\n                        } else {\n                            list.add(signatureInfo)\n                        }\n                    }\n                }\n            }\n        }\n        println(\"All loaded\")\n\n        while (true) {\n            val line = readLine()\n            map[line]?.let { it.forEach { dumpSignatureInfo(it)} }\n        }\n    } catch (e: StorageException) {\n        e.printStackTrace()\n    }\n\n}\n"
  },
  {
    "path": "signature-viewer/src/org/jetbrains/ruby/runtime/signature/SplitDB.kt",
    "content": "package org.jetbrains.ruby.runtime.signature\n\nimport org.jetbrains.exposed.sql.Database\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.types.signature.GemInfo\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoRow\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.CallInfoTable\nimport java.nio.file.Paths\n\nval gemToDBMap = HashMap<GemInfo?, Database>()\n\nfun gemToDB(info: GemInfo?, outputDir: String, rubyVersion: String): Database =\n        gemToDBMap[info] ?: DatabaseProvider.connectToDB(Paths.get(outputDir,\n                \"${info?.name?.plus(\"-\")?.plus(info.version) ?: \"no_gem\"}-ruby-$rubyVersion\" + DatabaseProvider.H2_DB_FILE_EXTENSION).toString())\n                .also { gemToDBMap[info] = it }\n\nfun input(msg: String): String {\n    println(msg)\n    return readLine()!!\n}\n\n/**\n * This small script splits massive database into small databases. Each\n * small database is responsible for particular gem and named accordingly\n */\nfun main(args: Array<String>) {\n    val dpPath = parseDBViewerCommandLineArgs(args)\n    val input = DatabaseProvider.connectToDB(dpPath)\n\n    val outputDir = input(\"Enter output dir: \")\n    val rubyVersion = input(\"Enter ruby version: \")\n\n    transaction(input) {\n        CallInfoRow.all().forEach {\n            val callInfo = it.copy()\n            transaction(gemToDB(callInfo.methodInfo.classInfo.gemInfo, outputDir, rubyVersion)) {\n                CallInfoTable.insertInfoIfNotContains(callInfo)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "state-tracker/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.2.70'\n\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nversion 'unspecified'\n\napply plugin: 'java'\napply plugin: 'kotlin'\n\nsourceCompatibility = 1.8\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    compile \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\n    testCompile group: 'junit', name: 'junit', version: '4.12'\n}\n\ncompileKotlin {\n    kotlinOptions.jvmTarget = \"1.8\"\n}\ncompileTestKotlin {\n    kotlinOptions.jvmTarget = \"1.8\"\n}\n\nsourceSets {\n    main.java.srcDirs = ['src/main/java']\n    test.java.srcDirs = ['src/test/java']\n    test.resources.srcDirs=['src/test/java/testData']\n}"
  },
  {
    "path": "state-tracker/src/main/java/org/jetbrains/ruby/stateTracker/RubyClassHierarchy.kt",
    "content": "package org.jetbrains.ruby.stateTracker\n\ninterface RubyClassHierarchy {\n    val loadPaths: List<String>\n\n    val topLevelConstants: Map<String, RubyConstant>\n\n    fun getRubyModule(fqn: String) : RubyModule?\n\n    class Impl(override val loadPaths: List<String>, rubyModules: List<RubyModule>,\n               override val topLevelConstants: Map<String, RubyConstant>) : RubyClassHierarchy {\n\n        private val name2modules  = rubyModules.associateBy( {it.name} , {it})\n\n        override fun getRubyModule(fqn: String): RubyModule? {\n            return name2modules[fqn]\n        }\n    }\n}\n\ninterface RubyConstant {\n    val name: String\n    val type: String\n    val extended: List<String>\n    data class Impl(override val name: String,\n                    override val type: String,\n                    override val extended: List<String>) : RubyConstant\n}\n\ninterface RubyModule {\n    val name: String\n    val classDirectAncestors: List<RubyModule>\n    val instanceDirectAncestors: List<RubyModule>\n    val classMethods: List<RubyMethod>\n    val instanceMethods: List<RubyMethod>\n\n    class Impl(override val name: String,\n               override val classDirectAncestors: List<RubyModule>,\n               override val instanceDirectAncestors: List<RubyModule>,\n               override val classMethods: List<RubyMethod>,\n               override val instanceMethods: List<RubyMethod>) : RubyModule\n}\n\ninterface RubyClass: RubyModule {\n    val superClass : RubyClass\n\n    class Impl(override val name: String,\n               override val classDirectAncestors: List<RubyModule>,\n               override val instanceDirectAncestors: List<RubyModule>,\n               override val classMethods: List<RubyMethod>,\n               override val instanceMethods: List<RubyMethod>,\n               override val superClass: RubyClass) : RubyClass\n\n    companion object : RubyClass {\n        val EMPTY = this\n        override val name: String\n            get() = \"\"\n        override val classDirectAncestors: List<RubyModule>\n            get() = emptyList()\n        override val instanceDirectAncestors: List<RubyModule>\n            get() = emptyList()\n        override val classMethods: List<RubyMethod>\n            get() = emptyList()\n        override val instanceMethods: List<RubyMethod>\n            get() = emptyList()\n        override val superClass: RubyClass\n            get() = this\n    }\n}\n\ninterface RubyMethod {\n    val name: String\n    val location: Location?\n    val arguments: List<ArgInfo>\n    data class ArgInfo(val kind: ArgumentKind, val name: String)\n    class Impl(override val name: String, override val location: Location?,\n               override val arguments: List<ArgInfo>) : RubyMethod\n    enum class ArgumentKind {\n        REQ,\n        OPT,\n        REST,\n        KEY,\n        KEY_REST,\n        KEY_REQ,\n        BLOCK;\n\n        companion object {\n            fun fromString(name : String): ArgumentKind {\n                return when (name) {\n                    \"req\"      -> REQ\n                    \"opt\"      -> OPT\n                    \"rest\"     -> REST\n                    \"key\"      -> KEY\n                    \"keyrest\"  -> KEY_REST\n                    \"keyreq\"   -> KEY_REQ\n                    \"block\"    -> BLOCK\n                    else -> throw IllegalArgumentException(name)\n                }\n            }\n        }\n    }\n\n}\n\ninterface Location {\n    val path: String\n    val lineNo: Int\n\n    data class Impl(override val path: String, override val lineNo: Int) : Location\n}\n\n\n"
  },
  {
    "path": "state-tracker/src/main/java/org/jetbrains/ruby/stateTracker/RubyClassHierarchyLoader.kt",
    "content": "package org.jetbrains.ruby.stateTracker\n\nimport com.google.gson.Gson\nimport java.util.*\nimport kotlin.collections.ArrayList\n\nobject RubyClassHierarchyLoader {\n\n    private val gson = Gson()\n\n\n    fun mergeJsons(jsons: List<String>): String {\n        return gson.toJson(jsons.map { gson.fromJson(it, Root::class.java) }.reduce { a, b -> joinRoots(a, b) })\n    }\n\n    fun fromJson(json: String): RubyClassHierarchy {\n        val root = gson.fromJson(json, Root::class.java)\n        return RubyClassHierarchy.Impl(root.load_path,\n                                       MapHelper(TopsortHelper(root.modules).topsort()).map(),\n                                       root.top_level_constants.associate { Pair(it.name, RubyConstant.Impl(\n                                               it.name,\n                                               it.class_name,\n                                               it.extended\n                                       )) })\n    }\n\n    private fun joinRoots(one: Root, another: Root) : Root {\n        return Root( joinTopLevelConstants(one.top_level_constants, another.top_level_constants),\n                     joinLoadPath(one.load_path, another.load_path),\n                     joinModules(one.modules, another.modules)\n        )\n    }\n\n    private fun joinTopLevelConstants(one: List<TopLevelConstant>, another: List<TopLevelConstant>): List<TopLevelConstant> {\n        return one.union(another).associateBy(TopLevelConstant::name).values.toList()\n    }\n\n    private fun joinLoadPath(one: List<String>, another: List<String>): List<String> = one.union(another).toList()\n\n    private fun joinModules(one: List<Module>, another: List<Module>): List<Module> {\n        return one.union(another).associateBy(Module::name).values.toList()\n    }\n\n    private data class Method(var name: String,\n                      var path: String?,\n                      var line: String?,\n                      var parameters: List<List<String>>)\n\n    private data class Module(var name: String,\n                              var type: String,\n                              var superclass: String?,\n                              var singleton_class_ancestors: List<String>?,\n                              var ancestors: List<String>?,\n                              var class_methods: List<Method>,\n                              var instance_methods: List<Method>)\n\n    private data class TopLevelConstant(var name: String,\n                                        var class_name: String,\n                                        var extended: List<String>)\n\n    private data class Root(var top_level_constants: List<TopLevelConstant>,\n                            var load_path: List<String>, var modules: List<Module>)\n\n    private class MapHelper(val topsortedList: List<Module>) {\n        private val name2RubyModule = HashMap<String, RubyModule>()\n        private val name2Module = topsortedList.associateBy { it.name }\n\n        fun map() : List<RubyModule> = topsortedList.map { toRubyModule(it) }\n\n        private fun toRubyModule(module: Module): RubyModule {\n            val rubyModule = when (module.type) {\n                \"Module\" -> createModule(module)\n                \"Class\" -> createClass(module)\n                //TODO some module/class objects can have type derived from Module/Class.\n                //For example: RSpec::Rails::AssertionDelegator\n                //lets have a look at superclass\n                else -> if (module.superclass.isNullOrBlank()) createModule(module) else createClass(module)\n            }\n            name2RubyModule[rubyModule.name] = rubyModule\n            return rubyModule\n        }\n\n        private fun createClass(module: Module): RubyClass.Impl {\n            return RubyClass.Impl(module.name,\n                    toRubyModules(removeAllNonDirectAncestors(module) { m -> m.singleton_class_ancestors }),\n                    toRubyModules(removeAllNonDirectAncestors(module) { m -> m.ancestors }),\n                    toRubyMethods(module.class_methods),\n                    toRubyMethods(module.instance_methods),\n                    (name2RubyModule[module.superclass] ?: RubyClass.EMPTY) as RubyClass)\n        }\n\n        private fun createModule(module: Module): RubyModule.Impl {\n            return RubyModule.Impl(module.name,\n                    toRubyModules(removeAllNonDirectAncestors(module) { m -> m.singleton_class_ancestors }),\n                    toRubyModules(removeAllNonDirectAncestors(module) { m -> m.ancestors }),\n                    toRubyMethods(module.class_methods),\n                    toRubyMethods(module.instance_methods))\n        }\n\n        private fun toRubyModules(names: List<String>): List<RubyModule> =\n                names.mapNotNull { name2RubyModule[it] }\n\n\n        private fun toRubyMethods(methods: List<Method>): List<RubyMethod> =\n                methods.map {\n                    RubyMethod.Impl(\n                            it.name,\n                            if (it.path != null && it.line != null) {\n                                Location.Impl(it.path!!, it.line!!.toInt())\n                            } else null,\n                            it.parameters.map {\n                                RubyMethod.ArgInfo(RubyMethod.ArgumentKind.fromString(it[0]),\n                                        if (it.size == 2) it[1] else \"\")\n                            })\n                }\n\n        /**\n         * Removes all non direct ancestors.\n         *\n         * @param ancestorGetter the rule which by given [Module] gives it ancestor (for example it\n         * may return [Module.ancestors] or [Module.singleton_class_ancestors] by given [Module])\n         * @return [List] where all non direct ancestors are excluded\n         */\n        private fun removeAllNonDirectAncestors(module: Module, ancestorGetter: (Module) -> (List<String>?)): List<String> {\n            val toRemove = HashSet<String>()\n            ancestorGetter(module)?.forEach {\n                val firstLevelAncestor: String = it\n                if (firstLevelAncestor != module.name && !toRemove.contains(firstLevelAncestor)) {\n                    name2Module[firstLevelAncestor]?.let {\n                        ancestorGetter(it)?.forEach {\n                            val secondLevelAncestor: String = it\n                            if (secondLevelAncestor != firstLevelAncestor) toRemove.add(secondLevelAncestor)\n                        }\n                    }\n                }\n            }\n            return ancestorGetter(module)?.filter { !toRemove.contains(it) } ?: listOf()\n        }\n    }\n\n    private class TopsortHelper(val modules: List<Module>) {\n        private val visited = HashSet<String>()\n        private val result = ArrayList<Module>()\n        private val name2Module = modules.associateBy { it.name }\n\n        fun topsort(): List<Module> {\n            visited.add(\"\")\n            modules.forEach { tryVisit(it.name) }\n            return result\n        }\n\n        private fun dfs(module: Module) {\n            tryVisit(module.superclass)\n            module.ancestors?.forEach {tryVisit(it)}\n            module.singleton_class_ancestors?.forEach {tryVisit(it)}\n            result.add(module)\n        }\n\n        private fun tryVisit(name: String?) {\n            if (name == null) return\n            if (visited.add(name)) {\n                name2Module[name]?.let { dfs(it) }\n            }\n        }\n\n    }\n\n}\n\n"
  },
  {
    "path": "state-tracker/src/test/java/org/jetbrains/ruby/stateTracker/RubyClassHierarchyLoaderNonStandardModuleTypeTest.kt",
    "content": "package org.jetbrains.ruby.stateTracker\n\nimport junit.framework.TestCase\nimport org.junit.Test\n\nclass RubyClassHierarchyLoaderNonStandardModuleTypeTest : TestCase() {\n    private var classHierarchy : RubyClassHierarchy? = null\n\n    override fun setUp() {\n        val inputStream = javaClass.classLoader.getResourceAsStream(\"non-standard-module-type.json\")\n        val inputString = inputStream.bufferedReader().use { it.readText() }\n        classHierarchy = RubyClassHierarchyLoader.fromJson(inputString)\n    }\n\n    @Test\n    fun testHierarchyLoaded() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            assertNotNull(it.getRubyModule(\"AAAA\"))\n            assertNotNull(it.getRubyModule(\"BBBB\"))\n        }\n    }\n\n}"
  },
  {
    "path": "state-tracker/src/test/java/org/jetbrains/ruby/stateTracker/RubyClassHierarchyLoaderTest.kt",
    "content": "package org.jetbrains.ruby.stateTracker\n\nimport junit.framework.TestCase\nimport org.junit.Test\n\nclass RubyClassHierarchyLoaderTest : TestCase() {\n\n    private var classHierarchy : RubyClassHierarchy? = null\n\n    override fun setUp() {\n        val inputStream = javaClass.classLoader.getResourceAsStream(\"classes.json\")\n        val inputString = inputStream.bufferedReader().use { it.readText() }\n        classHierarchy = RubyClassHierarchyLoader.fromJson(inputString)\n    }\n\n    @Test\n    fun testHasBasicObject() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            assertNotNull(it.getRubyModule(\"BasicObject\"))\n        }\n    }\n\n    @Test\n    fun testIncluded() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val module = it.getRubyModule(\"Gem::Resolver::Molinillo::Resolver::Resolution\")\n            assertNotNull(module)\n            assertTrue(module!!.instanceDirectAncestors.any {it.name == \"Kernel\"})\n            assertTrue(module.instanceDirectAncestors.any {it.name == \"Gem::Resolver::Molinillo::Delegates::ResolutionState\"})\n        }\n    }\n\n    @Test\n    fun testAllNonDirectAncestorsAreExcluded() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val module = it.getRubyModule(\"CGI\")\n            assertNotNull(module)\n            assertTrue(module!!.classDirectAncestors.none {it.name == \"Kernel\"})\n            assertTrue(module.classDirectAncestors.any {it.name == \"CGI::Util\"})\n        }\n    }\n\n    @Test\n    fun testSuperClass() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val module = it.getRubyModule(\"Timeout::Error\") as RubyClass\n            assertTrue(module.superClass.name == \"RuntimeError\")\n        }\n    }\n\n    @Test\n    fun testHasMethod() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val module = it.getRubyModule(\"Timeout::Error\") as RubyClass\n            val expectedLocation = Location.Impl(\"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb\",\n                    28)\n            assertTrue(module.instanceMethods.any{it.name == \"thread\" && it.location == expectedLocation })\n        }\n    }\n\n    @Test\n    fun testConstants() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val elem = it.topLevelConstants[\"STDIN\"]\n            assertNotNull(elem)\n            assertTrue(elem!!.extended.isEmpty())\n            assertTrue(elem.name == \"STDIN\")\n            assertTrue(elem.type == \"IO\")\n        }\n    }\n\n    @Test\n    fun testParameters() {\n        assertNotNull(classHierarchy)\n        classHierarchy?.let {\n            val module = it.getRubyModule(\"Dir::Tmpname\")!!\n            assertTrue(module.classMethods.any {\n                it.name == \"create\" &&\n                        it.arguments.any { it.kind == RubyMethod.ArgumentKind.KEY_REST } &&\n                        it.arguments.any { it.kind == RubyMethod.ArgumentKind.OPT } &&\n                        it.arguments.any { it.kind == RubyMethod.ArgumentKind.KEY } &&\n                        it.arguments.any { it.kind == RubyMethod.ArgumentKind.REQ }\n            })\n        }\n    }\n}"
  },
  {
    "path": "state-tracker/src/test/java/testData/classes.json",
    "content": "{\n  \"top_level_constants\": [\n    {\n      \"class_name\": \"IO\",\n      \"extended\": [],\n      \"name\": \"STDIN\"\n    }\n  ],\n\n  \"modules\": [\n    {\n      \"name\": \"Gem::Resolver::Molinillo::Resolver::Resolution\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Gem::Resolver::Molinillo::Resolver::Resolution\",\n        \"Gem::Resolver::Molinillo::Delegates::SpecificationProvider\",\n        \"Gem::Resolver::Molinillo::Delegates::ResolutionState\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"base\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 37\n        },\n        {\n          \"name\": \"resolve\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 63\n        },\n        {\n          \"name\": \"specification_provider\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 29\n        },\n        {\n          \"name\": \"resolver_ui\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 33\n        },\n        {\n          \"name\": \"original_requested\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 40\n        },\n        {\n          \"name\": \"iteration_rate=\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 88\n        },\n        {\n          \"name\": \"started_at=\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 92\n        },\n        {\n          \"name\": \"states=\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/resolution.rb\",\n          \"line\": 96\n        }\n      ],\n      \"superclass\": \"Object\"\n    },\n    {\n      \"name\": \"CGI\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"CGI::Escape\",\n        \"CGI::Util\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"CGI\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n        {\n          \"name\": \"parse\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"query\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 375\n        },\n        {\n          \"name\": \"accept_charset\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 740\n        },\n        {\n          \"name\": \"accept_charset=\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"accept_charset\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 745\n        }\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"print\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"options\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 365\n        },\n        {\n          \"name\": \"out\",\n          \"parameters\": [\n            [\n              \"opt\",\n              \"options\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 349\n        },\n        {\n          \"name\": \"header\",\n          \"parameters\": [\n            [\n              \"opt\",\n              \"options\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 153\n        },\n        {\n          \"name\": \"http_header\",\n          \"parameters\": [\n            [\n              \"opt\",\n              \"options\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 153\n        },\n        {\n          \"name\": \"nph?\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 256\n        },\n        {\n          \"name\": \"accept_charset\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/core.rb\",\n          \"line\": 750\n        }\n      ],\n      \"superclass\": \"Object\"\n    },\n    {\n      \"name\": \"Timeout::Error\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Timeout::Error\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n        {\n          \"name\": \"catch\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"args\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb\",\n          \"line\": 30\n        }\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"exception\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb\",\n          \"line\": 36\n        },\n        {\n          \"name\": \"thread\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb\",\n          \"line\": 28\n        }\n      ],\n      \"superclass\": \"RuntimeError\"\n    },\n    {\n      \"name\": \"Dir::Tmpname\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Dir::Tmpname\"\n      ],\n      \"class_methods\": [\n        {\n          \"name\": \"create\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"basename\"\n            ],\n            [\n              \"opt\",\n              \"tmpdir\"\n            ],\n            [\n              \"key\",\n              \"max_try\"\n            ],\n            [\n              \"keyrest\",\n              \"opts\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/tmpdir.rb\",\n          \"line\": 121\n        },\n        {\n          \"name\": \"tmpdir\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/tmpdir.rb\",\n          \"line\": 105\n        },\n        {\n          \"name\": \"make_tmpname\",\n          \"parameters\": [\n            [\n              \"req\"\n            ],\n            [\n              \"req\",\n              \"n\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/tmpdir.rb\",\n          \"line\": 109\n        }\n      ],\n      \"instance_methods\": [\n\n      ]\n    },\n    {\n      \"name\": \"RequireAll\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"RequireAll\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"require_all\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"args\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 34\n        },\n        {\n          \"name\": \"require_rel\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"paths\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 146\n        },\n        {\n          \"name\": \"load_all\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"paths\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 158\n        },\n        {\n          \"name\": \"load_rel\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"paths\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 164\n        },\n        {\n          \"name\": \"autoload_all\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"paths\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 210\n        },\n        {\n          \"name\": \"autoload_rel\",\n          \"parameters\": [\n            [\n              \"rest\",\n              \"paths\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib/require_all.rb\",\n          \"line\": 224\n        }\n      ]\n    },\n    {\n      \"name\": \"Kernel\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n        {\n          \"name\": \"`\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"gets\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"proc\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"lambda\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"sprintf\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"format\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Integer\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Float\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"String\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Array\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Hash\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"select\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"local_variables\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"warn\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"raise\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"fail\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"global_variables\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"__method__\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"__callee__\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"__dir__\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"eval\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"iterator?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"block_given?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"catch\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"throw\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"loop\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"trace_var\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"untrace_var\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"at_exit\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"load\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"syscall\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"open\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"printf\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"print\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"putc\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"puts\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"readline\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"readlines\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"p\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"test\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"rand\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"srand\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"trap\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"require\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"require_relative\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"autoload\",\n          \"parameters\": [\n            [\n              \"req\"\n            ],\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"autoload?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"binding\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"caller\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"caller_locations\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"fork\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"exit\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"sleep\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"exec\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"exit!\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"system\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"spawn\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"abort\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Rational\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"Complex\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"set_trace_func\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"URI\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"uri\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/uri/common.rb\",\n          \"line\": 733\n        }\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"instance_of?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"kind_of?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"is_a?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"tap\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"public_send\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"method\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"public_method\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"singleton_method\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"remove_instance_variable\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"define_singleton_method\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"instance_variable_set\",\n          \"parameters\": [\n            [\n              \"req\"\n            ],\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"extend\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"to_enum\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"enum_for\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"<=>\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"===\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"=~\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"!~\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"eql?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"respond_to?\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"freeze\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"inspect\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"object_id\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"send\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"display\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"to_s\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"nil?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"hash\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"class\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"singleton_class\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"clone\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"dup\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"itself\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"taint\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"tainted?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"untaint\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"untrust\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"untrusted?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"trust\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"frozen?\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"methods\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"singleton_methods\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"protected_methods\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"private_methods\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"public_methods\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"instance_variable_get\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"instance_variables\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"instance_variable_defined?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Gem::Resolver::Molinillo::Delegates::SpecificationProvider\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Gem::Resolver::Molinillo::Delegates::SpecificationProvider\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"search_for\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"dependency\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 8\n        },\n        {\n          \"name\": \"dependencies_for\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"specification\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 15\n        },\n        {\n          \"name\": \"requirement_satisfied_by?\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"requirement\"\n            ],\n            [\n              \"req\",\n              \"activated\"\n            ],\n            [\n              \"req\",\n              \"spec\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 22\n        },\n        {\n          \"name\": \"name_for\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"dependency\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 29\n        },\n        {\n          \"name\": \"allow_missing?\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"dependency\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 57\n        },\n        {\n          \"name\": \"sort_dependencies\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"dependencies\"\n            ],\n            [\n              \"req\",\n              \"activated\"\n            ],\n            [\n              \"req\",\n              \"conflicts\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 50\n        },\n        {\n          \"name\": \"name_for_explicit_dependency_source\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 36\n        },\n        {\n          \"name\": \"name_for_locking_dependency_source\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb\",\n          \"line\": 43\n        }\n      ]\n    },\n    {\n      \"name\": \"Gem::Resolver::Molinillo::Delegates::ResolutionState\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Gem::Resolver::Molinillo::Delegates::ResolutionState\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"name\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 8\n        },\n        {\n          \"name\": \"requirements\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 14\n        },\n        {\n          \"name\": \"requirement\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 26\n        },\n        {\n          \"name\": \"conflicts\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 44\n        },\n        {\n          \"name\": \"activated\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 20\n        },\n        {\n          \"name\": \"depth\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 38\n        },\n        {\n          \"name\": \"possibilities\",\n          \"parameters\": [\n\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb\",\n          \"line\": 32\n        }\n      ]\n    },\n    {\n      \"name\": \"Object\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Object\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n\n      ],\n      \"superclass\": \"BasicObject\"\n    },\n    {\n      \"name\": \"CGI::Escape\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"CGI::Escape\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"escape\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"unescape\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"escapeHTML\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"unescapeHTML\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"CGI::Util\",\n      \"type\": \"Module\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"CGI::Util\",\n        \"CGI::Escape\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"escape\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"h\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"unescape\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"rfc1123_date\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"time\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 183\n        },\n        {\n          \"name\": \"escapeHTML\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"unescapeHTML\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"escape_html\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"unescape_html\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"escapeElement\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"string\"\n            ],\n            [\n              \"rest\",\n              \"elements\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 136\n        },\n        {\n          \"name\": \"unescapeElement\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"string\"\n            ],\n            [\n              \"rest\",\n              \"elements\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 156\n        },\n        {\n          \"name\": \"escape_element\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"string\"\n            ],\n            [\n              \"rest\",\n              \"elements\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 136\n        },\n        {\n          \"name\": \"unescape_element\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"string\"\n            ],\n            [\n              \"rest\",\n              \"elements\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 156\n        },\n        {\n          \"name\": \"pretty\",\n          \"parameters\": [\n            [\n              \"req\",\n              \"string\"\n            ],\n            [\n              \"opt\",\n              \"shift\"\n            ]\n          ],\n          \"path\": \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/cgi/util.rb\",\n          \"line\": 207\n        }\n      ]\n    },\n    {\n      \"name\": \"RuntimeError\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"RuntimeError\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n\n      ],\n      \"superclass\": \"StandardError\"\n    },\n    {\n      \"name\": \"BasicObject\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"BasicObject\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"!\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"==\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"!=\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"__send__\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"equal?\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"instance_eval\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"instance_exec\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"__id__\",\n          \"parameters\": [\n\n          ]\n        }\n      ],\n      \"superclass\": null\n    },\n    {\n      \"name\": \"StandardError\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"StandardError\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n\n      ],\n      \"instance_methods\": [\n\n      ],\n      \"superclass\": \"Exception\"\n    },\n    {\n      \"name\": \"Exception\",\n      \"type\": \"Class\",\n      \"singleton_class_ancestors\": [\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"ancestors\": [\n        \"Exception\",\n        \"RequireAll\",\n        \"Kernel\"\n      ],\n      \"class_methods\": [\n        {\n          \"name\": \"exception\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        }\n      ],\n      \"instance_methods\": [\n        {\n          \"name\": \"==\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"respond_to?\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"inspect\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"to_s\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"exception\",\n          \"parameters\": [\n            [\n              \"rest\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"message\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"backtrace\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"backtrace_locations\",\n          \"parameters\": [\n\n          ]\n        },\n        {\n          \"name\": \"set_backtrace\",\n          \"parameters\": [\n            [\n              \"req\"\n            ]\n          ]\n        },\n        {\n          \"name\": \"cause\",\n          \"parameters\": [\n\n          ]\n        }\n      ],\n      \"superclass\": \"Object\"\n    }\n  ],\n  \"load_path\": [\n    \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1@global/gems/did_you_mean-1.1.0/lib\",\n    \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/require_all-1.4.0/lib\",\n    \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/gems/json-2.1.0/lib\",\n    \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1/extensions/x86_64-darwin-16/2.4.0/json-2.1.0\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby/2.4.0/x86_64-darwin16\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/site_ruby\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/vendor_ruby/2.4.0\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/vendor_ruby/2.4.0/x86_64-darwin16\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/vendor_ruby\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0\",\n    \"/Users/vkkoshelev/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/x86_64-darwin16\"\n  ]\n}"
  },
  {
    "path": "state-tracker/src/test/java/testData/non-standard-module-type.json",
    "content": "{\n  \"top_level_constants\": [\n    {\n      \"class_name\": \"IO\",\n      \"extended\": [],\n      \"name\": \"STDIN\"\n    }\n  ],\n  \"load_path\": [\n    \"/Users/vkkoshelev/.rvm/gems/ruby-2.4.1@global/gems/did_you_mean-1.1.0/li\"\n  ],\n\n  \"modules\": [\n    {\n      \"name\": \"AAAA\",\n      \"type\": \"BBBB\",\n      \"singleton_class_included\": [\n      ],\n      \"included\": [\n      ],\n      \"class_methods\": [\n      ],\n      \"instance_methods\": [\n      ]\n    },\n    {\n      \"name\": \"BBBB\",\n      \"type\": \"Module\",\n      \"singleton_class_included\": [\n      ],\n      \"included\": [\n      ],\n      \"class_methods\": [\n      ],\n      \"instance_methods\": [\n      ],\n      \"superclass\": \"Module\"\n    }\n  ]\n}\n"
  },
  {
    "path": "storage-server-api/build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n    }\n\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\ndependencies {\n    compile project(':common')\n    compile project(':ruby-call-signature')\n\n    compile \"org.jetbrains.exposed:exposed:$exposedVersion\"\n    compile 'com.h2database:h2:1.4.197'\n}\n\nsourceSets {\n    main.java.srcDirs = ['src/main/java']\n    main.kotlin.srcDirs = ['src/main/java']\n\n    test.kotlin.srcDirs = ['src/test/java']\n}"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/signature/serialization/BlobSerialization.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.signature.serialization\n\nimport org.jetbrains.exposed.dao.EntityHook\nimport org.jetbrains.exposed.sql.transactions.TransactionManager\nimport org.jetbrains.ruby.codeInsight.types.signature.SignatureContract\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.SignatureContractRow\nimport java.io.DataInputStream\nimport java.io.DataOutputStream\nimport java.sql.Blob\nimport java.util.concurrent.CopyOnWriteArrayList\nimport kotlin.reflect.KProperty\n\nclass BlobDeserializer {\n    companion object {\n        private val openBlobs: MutableCollection<Blob> = CopyOnWriteArrayList()\n\n        init {\n            EntityHook.subscribe {\n                openBlobs.forEach { it.free() }\n                openBlobs.clear()\n            }\n        }\n    }\n\n    @Volatile\n    private var cachedContract: SignatureContract? = null\n\n    operator fun getValue(signatureContractRow: SignatureContractRow, property: KProperty<*>): SignatureContract {\n        cachedContract?.let { return it }\n\n        val blob = signatureContractRow.contractRaw\n        try {\n            val result = SignatureContract(DataInputStream(blob.binaryStream))\n            cachedContract = result\n            return result\n        } finally {\n            blob.free()\n        }\n    }\n\n    operator fun setValue(signatureContractRow: SignatureContractRow, property: KProperty<*>, signatureContract: SignatureContract) {\n        val blob = TransactionManager.current().connection.createBlob()\n        openBlobs.add(blob)\n\n        BlobSerializer.writeToBlob(signatureContract, blob)\n        signatureContractRow.contractRaw = blob\n        cachedContract = signatureContract\n    }\n}\n\nobject BlobSerializer {\n    fun writeToBlob(signatureContract: SignatureContract, blob: Blob): Blob {\n        val binaryStream = blob.setBinaryStream(1)\n        signatureContract.serialize(DataOutputStream(binaryStream))\n        binaryStream.close()\n        return blob\n    }\n}"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/DatabaseProvider.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server\n\nimport org.jetbrains.exposed.sql.Database\nimport org.jetbrains.exposed.sql.SchemaUtils\nimport org.jetbrains.exposed.sql.Transaction\nimport org.jetbrains.exposed.sql.selectAll\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.Logger\nimport org.jetbrains.ruby.codeInsight.injector\nimport org.jetbrains.ruby.codeInsight.types.storage.server.impl.*\n\nobject DatabaseProvider {\n    var defaultDatabase: Database? = null\n        private set\n    /**\n     * Default database file path with .mv.db suffix included\n     */\n    var defaultDatabaseFilePath: String? = null\n        private set\n    private const val IN_MEMORY_URL = \"jdbc:h2:mem:test\"\n    private const val H2_DRIVER = \"org.h2.Driver\"\n    const val H2_DB_FILE_EXTENSION = \".mv.db\"\n    private val logger: Logger = injector.getLogger(DatabaseProvider::class.java)\n\n    @JvmStatic\n    fun connectToInMemoryDB(isDefaultDatabase: Boolean = false): Database {\n        val database = Database.connect(IN_MEMORY_URL, driver = H2_DRIVER)\n        if (isDefaultDatabase) {\n            defaultDatabase = database\n        }\n        logger.info(\"Connected to in memory DB\")\n        logDatabaseSize(database)\n        return database\n    }\n\n    @JvmStatic\n    fun connectToDB(filePath: String, isDefaultDatabase: Boolean = false): Database {\n        check(filePath.endsWith(H2_DB_FILE_EXTENSION)) {\n            \"File path must end with $H2_DB_FILE_EXTENSION suffix\"\n        }\n        val filePathForUrl = filePath.substring(0, filePath.lastIndexOf(H2_DB_FILE_EXTENSION))\n        val database = Database.connect(\"jdbc:h2:$filePathForUrl\", driver = H2_DRIVER)\n        if (isDefaultDatabase) {\n            defaultDatabase = database\n            defaultDatabaseFilePath = filePath\n        }\n        logger.info(\"Connected to DB: $filePath\")\n        createAllDatabases(database)\n        logDatabaseSize(database)\n        return database\n    }\n\n    @JvmStatic\n    fun <T> defaultDatabaseTransaction(statement: Transaction.() -> T): T {\n        val defaultDatabaseLocal = defaultDatabase ?: throw IllegalStateException(\"Assign defaultDatabase firstly\")\n        return transaction(defaultDatabaseLocal, statement)\n    }\n\n    @JvmOverloads\n    fun createAllDatabases(db: Database? = null) {\n        transaction(db ?: defaultDatabase) {\n            SchemaUtils.create(GemInfoTable, ClassInfoTable, MethodInfoTable, SignatureTable, CallInfoTable)\n        }\n    }\n\n    @JvmOverloads\n    fun dropAllDatabases(db: Database? = null) {\n        transaction(db ?: defaultDatabase) {\n            SchemaUtils.drop(GemInfoTable, ClassInfoTable, MethodInfoTable, SignatureTable, CallInfoTable)\n        }\n    }\n\n    private fun logDatabaseSize(db: Database) {\n        transaction(db) {\n            for (table in listOf(CallInfoTable, MethodInfoTable, ClassInfoTable, SignatureTable, GemInfoTable)) {\n                logger.info(\"${table.tableName} table's number of rows ${table.selectAll().count()}\")\n            }\n        }\n    }\n}"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/RSignatureProvider.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.ruby.codeInsight.types.signature.*;\n\nimport java.util.Collection;\n\n/**\n * <p>An interface that allows for transparent working with the signatures storage.</p>\n * <p>\n * <p>The general workflow is the following:</p>\n * <ul>\n * <li>1. Determine which gem statistics are to be used. If one wants to receive code insight for some project,\n * they must know which gems are available at runtime.\n * <li>2. Since a precalculated information for the particular gem may not be available, one searches for the\n * closest gem version with calculated stats via {@link #getClosestRegisteredGem(GemInfo)}\n * <li>3. In order to get the registered classes available upon requiring the given gem one may use\n * {@link #getRegisteredClasses(GemInfo)}\n * <li>4. Given a class of a receiver object one may get the registered methods available for sending\n * via {@link #getRegisteredMethods(ClassInfo)}\n * <li>5. Given a call, which is represented as a method of a particular class in a particular gem one may\n * get Signature contract via {@link #getSignature(MethodInfo)}. It allows for getting params\n * information, deducing return type from given input types, etc.\n * </ul>\n */\npublic interface RSignatureProvider {\n    @NotNull\n    Collection<GemInfo> getRegisteredGems() throws StorageException;\n\n    @Nullable\n    GemInfo getClosestRegisteredGem(@NotNull GemInfo usedGem) throws StorageException;\n\n    @NotNull\n    Collection<ClassInfo> getRegisteredClasses(@NotNull GemInfo gem) throws StorageException;\n\n    @NotNull\n    Collection<ClassInfo> getAllClassesWithFQN(@NotNull String fqn) throws StorageException;\n\n    @NotNull\n    Collection<MethodInfo> getRegisteredMethods(@NotNull ClassInfo containerClass)\n            throws StorageException;\n\n    /**\n     * Get registered {@link CallInfo}s by given {@code methodInfo}\n     */\n    @NotNull\n    Collection<CallInfo> getRegisteredCallInfos(@NotNull MethodInfo methodInfo) throws StorageException;\n\n    @Nullable\n    SignatureInfo getSignature(@NotNull MethodInfo method) throws StorageException;\n\n    void deleteSignature(@NotNull MethodInfo method) throws StorageException;\n\n    void putSignature(@NotNull SignatureInfo signatureInfo) throws StorageException;\n\n}\n"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/RSignatureStorage.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.jetbrains.ruby.codeInsight.types.signature.*;\n\nimport java.util.Collection;\n\npublic interface RSignatureStorage<T extends RSignatureStorage.Packet> extends RSignatureProvider {\n\n    default void readPacket(@NotNull T packet) throws StorageException {\n        for (final SignatureInfo signatureInfo : packet.getSignatures()) {\n            final MethodInfo methodInfo = signatureInfo.getMethodInfo();\n            final SignatureInfo oldSignature = getSignature(methodInfo);\n\n            RSignatureContract contract;\n            if (oldSignature != null &&\n                    (contract = RSignatureContract.mergeMutably(oldSignature.getContract(), signatureInfo.getContract())) != null) {\n                putSignature(SignatureInfoKt.SignatureInfo(methodInfo, contract));\n            } else {\n                putSignature(signatureInfo);\n            }\n        }\n    }\n\n    @NotNull\n    Collection<T> formPackets(@Nullable ExportDescriptor descriptor) throws StorageException;\n\n    class ExportDescriptor {\n        private final boolean myInclude;\n\n        @NotNull\n        private final Collection<GemInfo> myGemsToIncludeOrExclude;\n\n        public ExportDescriptor(boolean include, @NotNull Collection<GemInfo> gemsToIncludeOrExclude) {\n            myInclude = include;\n            myGemsToIncludeOrExclude = gemsToIncludeOrExclude;\n        }\n\n        public boolean isInclude() {\n            return myInclude;\n        }\n\n        @NotNull\n        public Collection<GemInfo> getGemsToIncludeOrExclude() {\n            return myGemsToIncludeOrExclude;\n        }\n    }\n\n    interface Packet {\n        Collection<SignatureInfo> getSignatures();\n    }\n}\n"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/StorageException.java",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server;\n\n@SuppressWarnings(\"unused\")\npublic class StorageException extends Exception {\n    public StorageException() {\n    }\n\n    public StorageException(String message) {\n        super(message);\n    }\n\n    public StorageException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public StorageException(Throwable cause) {\n        super(cause);\n    }\n\n    public StorageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n}\n"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/impl/IntIdTableWithPossibleDependency.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.impl\n\nimport org.jetbrains.exposed.dao.EntityID\nimport org.jetbrains.exposed.dao.IntEntity\nimport org.jetbrains.exposed.dao.IntIdTable\nimport org.jetbrains.exposed.sql.*\nimport org.jetbrains.exposed.sql.statements.InsertStatement\nimport org.jetbrains.exposed.sql.statements.UpdateBuilder\nimport org.jetbrains.exposed.sql.statements.UpdateStatement\nimport org.jetbrains.exposed.sql.transactions.transaction\n\n/**\n * Represents SQL table which can possibly have dependency (by having dependency we mean that `this` SQL table can\n * possibly have column where we store id which refers to some row in other table called [dependency])\n * @param dependency SQL table which rows can be possibly referred from `this` SQL table\n * @param T type of info stored in this SQL table\n * @param F type of info stored in [dependency] SQL table\n */\nabstract class IntIdTableWithPossibleDependency<in T, out F>(\n        private val dependency: IntIdTableWithPossibleDependency<F, *>?) : IntIdTable() {\n    /**\n     * Find id of row where [info] is located. **Call this function only inside [transaction] block**\n     */\n    fun findRowId(info: T): EntityID<Int>? {\n        if (info is IntEntity) {\n            return info.id\n        }\n\n        if (!validateInfo(info)) {\n            return null\n        }\n\n        return traverseDependencies(info).let {\n            it.joinedWithDependencies.select { it.searchCriteria }\n        }.firstOrNull()?.get(id)\n    }\n\n    /**\n     * Insert info into SQL table if [info] is not still in the table; otherwise updates information in row according to [info].\n     * **Call this function only inside [transaction] block**\n     *\n     * @return id of row where [info] was inserted or if SQL table already contains [info] than returns id of corresponding row\n     */\n    open fun insertInfoIfNotContains(info: T): EntityID<Int>? {\n        val dependencyId: EntityID<Int>? = convertInfoToDependencyFormant(info)?.let {\n            dependency?.insertInfoIfNotContains(it)\n        }\n        if (!validateInfoBeforeWritingToBuilder(info, dependencyId)) {\n            return null\n        }\n        var ret = findRowId(info)\n        if (ret != null) {\n            update(where = { id eq ret!! }) { updateStatementBuilder: UpdateStatement ->\n                writeInfoToBuilder(updateStatementBuilder, info, dependencyId)\n            }\n        } else {\n            ret = insertAndGetId { insertStatementBuilder: InsertStatement<EntityID<Int>> ->\n                writeInfoToBuilder(insertStatementBuilder, info, dependencyId)\n            }\n        }\n        removeInvalidInfo(info)\n        return ret\n    }\n\n    protected open fun removeInvalidInfo(validInfo: T) { }\n    protected open fun validateInfo(info: T): Boolean = true\n    protected open fun validateInfoBeforeWritingToBuilder(info: T, dependencyId: EntityID<Int>?) = validateInfo(info)\n    protected abstract fun writeInfoToBuilder(builder: UpdateBuilder<*>, info: T, dependencyId: EntityID<Int>?)\n    protected abstract fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: T): Op<Boolean>\n    protected abstract fun convertInfoToDependencyFormant(info: T): F?\n\n    private data class TraverseResult(var joinedWithDependencies: ColumnSet, var searchCriteria: Op<Boolean>)\n    private fun traverseDependencies(info: T): TraverseResult {\n        val searchCriteria = SqlExpressionBuilder.createSearchCriteriaForInfo(info)\n        val convertedInfo by lazy { convertInfoToDependencyFormant(info) }\n        if (dependency == null || convertedInfo == null) {\n            return TraverseResult(this, searchCriteria)\n        }\n\n        val ret = dependency.traverseDependencies(convertedInfo)\n        ret.joinedWithDependencies = ret.joinedWithDependencies.innerJoin(this)\n        ret.searchCriteria = ret.searchCriteria and searchCriteria\n\n        return ret\n    }\n}\n\n/**\n * @see IntIdTableWithPossibleDependency\n * @see IntIdTableWithDependency\n * @see IntIdTableWithNullableDependency\n */\nabstract class IntIdTableWithoutDependency<T> : IntIdTableWithPossibleDependency<T, Nothing>(null) {\n    final override fun convertInfoToDependencyFormant(info: T): Nothing? = null\n}\n\n/**\n * Represents SQL table with nullable [dependency]. (nullable dependency means that column which contains id refers\n * to some row in [dependency] table can possibly be `null`)\n *\n * @see IntIdTableWithPossibleDependency\n * @see IntIdTableWithoutDependency\n * @see IntIdTableWithDependency\n */\nabstract class IntIdTableWithNullableDependency<in T, out F>(dependency: IntIdTableWithPossibleDependency<F, *>) :\n        IntIdTableWithPossibleDependency<T, F>(dependency) {\n    final override fun validateInfoBeforeWritingToBuilder(info: T, dependencyId: EntityID<Int>?): Boolean {\n        return super.validateInfoBeforeWritingToBuilder(info, dependencyId)\n    }\n}\n\n/**\n * Represents SQL table with not nullable dependency (not nullable dependency means that column which contains id refers\n * to some row in [dependency] table cannot be `null`)\n *\n * @see IntIdTableWithPossibleDependency\n * @see IntIdTableWithoutDependency\n * @see IntIdTableWithNullableDependency\n */\nabstract class IntIdTableWithDependency<in T, out F>(dependency: IntIdTableWithPossibleDependency<F, *>) :\n        IntIdTableWithPossibleDependency<T, F>(dependency) {\n    final override fun validateInfoBeforeWritingToBuilder(info: T, dependencyId: EntityID<Int>?): Boolean {\n        return dependencyId != null && super.validateInfoBeforeWritingToBuilder(info, dependencyId)\n    }\n\n    final override fun writeInfoToBuilder(builder: UpdateBuilder<*>, info: T, dependencyId: EntityID<Int>?) {\n        /**\n         * can do unsafe dereference as soon as [dependencyId] was checked in [validateInfoBeforeWritingToBuilder]\n         */\n        writeInfoToBuilderNotNullableDependency(builder, info, dependencyId!!)\n    }\n\n    protected abstract fun writeInfoToBuilderNotNullableDependency(builder: UpdateBuilder<*>, info: T, dependencyId: EntityID<Int>)\n}\n"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/impl/RSignatureProviderImpl.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.impl\n\nimport org.jetbrains.exposed.sql.and\nimport org.jetbrains.exposed.sql.deleteWhere\nimport org.jetbrains.exposed.sql.select\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.RSignatureProvider\n\nobject RSignatureProviderImpl : RSignatureProvider {\n    override fun getRegisteredGems(): Collection<GemInfo> {\n        return DatabaseProvider.defaultDatabaseTransaction { GemInfoRow.all() }.map { it.copy() }\n    }\n\n    override fun getClosestRegisteredGem(usedGem: GemInfo): GemInfo? {\n        val (upperBound, lowerBound) = DatabaseProvider.defaultDatabaseTransaction {\n            val upperBound = GemInfoTable.select {\n                GemInfoTable.name.eq(usedGem.name) and GemInfoTable.version.greaterEq(usedGem.version)\n            }\n                    .orderBy(GemInfoTable.version)\n                    .limit(1)\n                    .firstOrNull()\n                    ?.let { GemInfoRow.wrapRow(it) }\n\n            val lowerBound = GemInfoTable.select {\n                GemInfoTable.name.eq(usedGem.name) and GemInfoTable.version.lessEq(usedGem.version)\n            }\n                    .orderBy(GemInfoTable.version, isAsc = false)\n                    .limit(1)\n                    .firstOrNull()\n                    ?.let { GemInfoRow.wrapRow(it) }\n            return@defaultDatabaseTransaction Pair(upperBound?.copy(), lowerBound?.copy())\n        }\n\n        if (lowerBound == null || upperBound == null) {\n            return lowerBound ?: upperBound\n        } else {\n            return if (firstStringCloser(usedGem.version, lowerBound.version, upperBound.version)) lowerBound else upperBound\n        }\n    }\n\n    override fun getRegisteredClasses(gem: GemInfo): Collection<ClassInfo> {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            val gemId = GemInfoTable.findRowId(gem) ?: return@defaultDatabaseTransaction emptyList()\n\n            return@defaultDatabaseTransaction ClassInfoRow.find { ClassInfoTable.gemInfo eq gemId }.map { it.copy() }\n        }\n    }\n\n    override fun getAllClassesWithFQN(fqn: String): Collection<ClassInfo> {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            ClassInfoRow.find { ClassInfoTable.fqn eq fqn }.map { it.copy() }\n        }\n    }\n\n    override fun getRegisteredMethods(containerClass: ClassInfo): Collection<MethodInfo> {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            val classId = ClassInfoTable.findRowId(containerClass) ?: return@defaultDatabaseTransaction emptyList()\n\n            return@defaultDatabaseTransaction MethodInfoRow.find { MethodInfoTable.classInfo eq classId }.map { it.copy() }\n        }\n    }\n\n    override fun getSignature(method: MethodInfo): SignatureInfo? {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            val methodId = MethodInfoTable.findRowId(method) ?: return@defaultDatabaseTransaction null\n\n            return@defaultDatabaseTransaction SignatureContractRow.find { SignatureTable.methodInfo eq methodId }.firstOrNull()?.copy()\n        }\n    }\n\n    override fun deleteSignature(method: MethodInfo) {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            val methodId = MethodInfoTable.findRowId(method) ?: return@defaultDatabaseTransaction\n\n            SignatureTable.deleteWhere { SignatureTable.methodInfo eq methodId }\n        }\n    }\n\n    override fun putSignature(signatureInfo: SignatureInfo) {\n        SignatureTable.insertInfoIfNotContains(signatureInfo)\n    }\n\n    override fun getRegisteredCallInfos(methodInfo: MethodInfo): List<CallInfo> {\n        return DatabaseProvider.defaultDatabaseTransaction {\n            val methodId = MethodInfoTable.findRowId(methodInfo) ?: return@defaultDatabaseTransaction emptyList()\n\n            return@defaultDatabaseTransaction CallInfoRow.find { CallInfoTable.methodInfoId eq methodId }.map { it.copy() }\n        }\n    }\n}\n\nfun firstStringCloser(gemVersion: String,\n                      firstVersion: String, secondVersion: String): Boolean {\n    val lcpLengthFirst = longestCommonPrefixLength(gemVersion, firstVersion)\n    val lcpLengthSecond = longestCommonPrefixLength(gemVersion, secondVersion)\n    return lcpLengthFirst > lcpLengthSecond || lcpLengthFirst > 0 && lcpLengthFirst == lcpLengthSecond &&\n            Math.abs(gemVersion.rawChar(lcpLengthFirst) - firstVersion.rawChar(lcpLengthFirst)) <\n                    Math.abs(gemVersion.rawChar(lcpLengthFirst) - secondVersion.rawChar(lcpLengthSecond))\n}\n\nprivate fun String.rawChar(index: Int): Int = if (index < length) this[index].toInt() else 0\n\nprivate fun longestCommonPrefixLength(str1: String, str2: String): Int {\n    val minLength = Math.min(str1.length, str2.length)\n    return (0 until minLength).firstOrNull { str1[it] != str2[it] } ?: minLength\n}\n"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/impl/RowConversions.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.impl\n\nimport org.jetbrains.exposed.sql.ResultRow\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.SignatureContract\nimport java.io.DataInputStream\n\nfun GemInfo(row: ResultRow): GemInfo = GemInfo(row[GemInfoTable.name], row[GemInfoTable.version])\n\nfun ClassInfo(row: ResultRow): ClassInfo = ClassInfo(GemInfo(row), row[ClassInfoTable.fqn])\n\nfun Location(row: ResultRow): Location? {\n    val locationFile = row[MethodInfoTable.locationFile]\n            ?: return null\n\n    return Location(locationFile, row[MethodInfoTable.locationLineno])\n}\n\nfun MethodInfo(row: ResultRow): MethodInfo = MethodInfo.Impl(\n        ClassInfo(row),\n        row[MethodInfoTable.name],\n        row[MethodInfoTable.visibility],\n        Location(row))\n\nfun SignatureInfo(row: ResultRow): SignatureInfo {\n    val blob = row[SignatureTable.contract]\n    try {\n        return SignatureInfo(MethodInfo(row), SignatureContract(DataInputStream(blob.binaryStream)))\n    } finally {\n        blob.free()\n    }\n}"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/impl/Schema.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.impl\n\nimport org.jetbrains.exposed.dao.EntityID\nimport org.jetbrains.exposed.dao.IntEntity\nimport org.jetbrains.exposed.dao.IntEntityClass\nimport org.jetbrains.exposed.sql.*\nimport org.jetbrains.exposed.sql.statements.UpdateBuilder\nimport org.jetbrains.exposed.sql.transactions.TransactionManager\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.BlobDeserializer\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.BlobSerializer\nimport java.sql.Blob\nimport kotlin.reflect.KProperty\n\nobject GemInfoTable : IntIdTableWithoutDependency<GemInfo>() {\n    val name = varchar(\"name\", GemInfo.LENGTH_OF_GEMNAME).index()\n    val version = varchar(\"version\", GemInfo.LENGTH_OF_GEMVERSION)\n\n    override fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: GemInfo): Op<Boolean> {\n        return (name eq info.name) and (version eq info.version)\n    }\n\n    override fun validateInfo(info: GemInfo): Boolean {\n        return info.name.length <= GemInfo.LENGTH_OF_GEMNAME && info.version.length <= GemInfo.LENGTH_OF_GEMVERSION\n    }\n\n    override fun writeInfoToBuilder(builder: UpdateBuilder<*>, info: GemInfo, dependencyId: EntityID<Int>?) {\n        builder[name] = info.name\n        builder[version] = info.version\n    }\n}\n\nclass GemInfoRow(id: EntityID<Int>) : IntEntity(id), GemInfo {\n    companion object : IntEntityClass<GemInfoRow>(GemInfoTable)\n\n    override var name: String by GemInfoTable.name\n    override var version: String by GemInfoTable.version\n\n    fun copy(): GemInfo = GemInfo(this)\n}\n\nobject ClassInfoTable : IntIdTableWithNullableDependency<ClassInfo, GemInfo>(GemInfoTable) {\n    val gemInfo = reference(\"gem_info\", GemInfoTable, ReferenceOption.CASCADE).nullable()\n    val fqn = varchar(\"fqn\", ClassInfo.LENGTH_OF_FQN).index()\n\n    override fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: ClassInfo): Op<Boolean> {\n        // HACK: as soon as fqn in RubyMine is not fully qualified (search criteria must be: fqn eq info.classFQN)\n        return fqn like \"%${info.classFQN}\"\n    }\n\n    override fun convertInfoToDependencyFormant(info: ClassInfo): GemInfo? {\n        return info.gemInfo\n    }\n\n    override fun validateInfo(info: ClassInfo): Boolean {\n        return info.classFQN.length <= ClassInfo.LENGTH_OF_FQN\n    }\n\n    override fun writeInfoToBuilder(builder: UpdateBuilder<*>, info: ClassInfo, dependencyId: EntityID<Int>?) {\n        builder[fqn] = info.classFQN\n        builder[gemInfo] = dependencyId\n    }\n}\n\nclass ClassInfoRow(id: EntityID<Int>) : IntEntity(id), ClassInfo {\n    companion object : IntEntityClass<ClassInfoRow>(ClassInfoTable)\n\n    override val gemInfo: GemInfoRow? by GemInfoRow optionalReferencedOn ClassInfoTable.gemInfo\n    override val classFQN: String by ClassInfoTable.fqn\n\n    fun copy(): ClassInfo = ClassInfo(this)\n}\n\nobject MethodInfoTable : IntIdTableWithDependency<MethodInfo, ClassInfo>(ClassInfoTable) {\n    val classInfo = reference(\"class_info\", ClassInfoTable, ReferenceOption.CASCADE)\n    val name = varchar(\"name\", MethodInfo.LENGTH_OF_NAME).index()\n    val visibility = enumeration(\"visibility\", RVisibility::class)\n    val locationFile = varchar(\"location_file\", MethodInfo.LENGTH_OF_PATH).nullable()\n    val locationLineno = integer(\"location_lineno\").default(0)\n\n    override fun convertInfoToDependencyFormant(info: MethodInfo): ClassInfo? {\n        return info.classInfo\n    }\n\n    override fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: MethodInfo): Op<Boolean> {\n        return name eq info.name\n    }\n\n    override fun validateInfo(info: MethodInfo): Boolean {\n        return info.name.length <= MethodInfo.LENGTH_OF_NAME &&\n                info.location?.let { it.path.length <= MethodInfo.LENGTH_OF_PATH } ?: true\n    }\n\n    override fun writeInfoToBuilderNotNullableDependency(builder: UpdateBuilder<*>, info: MethodInfo, dependencyId: EntityID<Int>) {\n        builder[classInfo] = dependencyId\n        builder[name] = info.name\n        builder[visibility] = info.visibility\n        builder[locationFile] = info.location?.path\n        builder[locationLineno] = info.location?.lineno ?: 0\n    }\n}\n\nclass MethodInfoRow(id: EntityID<Int>) : IntEntity(id), MethodInfo {\n    companion object : IntEntityClass<MethodInfoRow>(MethodInfoTable)\n\n    override var classInfo: ClassInfoRow by ClassInfoRow referencedOn MethodInfoTable.classInfo\n    override var name: String by MethodInfoTable.name\n    override var visibility: RVisibility by MethodInfoTable.visibility\n    override var location: Location? by object {\n        operator fun getValue(methodInfoRow: MethodInfoRow, property: KProperty<*>): Location? {\n            val file = MethodInfoTable.locationFile.getValue(methodInfoRow, property)\n            return file?.let { Location(it, MethodInfoTable.locationLineno.getValue(methodInfoRow, property)) }\n        }\n\n        operator fun setValue(methodInfoRow: MethodInfoRow, property: KProperty<*>, location: Location?) {\n            MethodInfoTable.locationFile.setValue(methodInfoRow, property, location?.path)\n            MethodInfoTable.locationLineno.setValue(methodInfoRow, property, location?.lineno ?: 0)\n        }\n    }\n\n    override fun toString(): String {\n        return name\n    }\n\n    fun copy(): MethodInfo = MethodInfo(this)\n}\n\n/**\n * Represent SQL table which contains information about every Ruby method call\n */\nobject CallInfoTable : IntIdTableWithDependency<CallInfo, MethodInfo>(MethodInfoTable) {\n    private const val ARGS_TYPES_STRING_LENGTH = 300\n    private const val RETURN_TYPE_STRING_LENGTH = 50\n    private const val CALL_INFOS_LIMIT_FOR_PARTICULAR_METHOD = 10\n\n    val methodInfoId = reference(\"method_info_id\", MethodInfoTable, ReferenceOption.NO_ACTION).index()\n\n    /**\n     * string containing types of unnamed args (e.g. REQ, KEYREQ args) splitted by separator\n     */\n    val unnamedArgsTypes = varchar(\"required_args_types\", ARGS_TYPES_STRING_LENGTH)\n\n    val namedArgsTypes = varchar(\"named_args_types\", ARGS_TYPES_STRING_LENGTH)\n\n    private val numberOfUnnamedArguments = integer(\"number_of_unnamed_arguments\")\n\n    val returnType = varchar(\"return_type\", RETURN_TYPE_STRING_LENGTH)\n\n    /**\n     * Deletes all info from [CallInfoTable] related to [methodInfo].\n     * **Call this function only inside [transaction] block.**\n     */\n    fun deleteAllInfoRelatedTo(methodInfo: MethodInfo) {\n        val methodInfoId = MethodInfoTable.findRowId(methodInfo) ?: return\n        CallInfoTable.deleteWhere {\n            CallInfoTable.methodInfoId eq methodInfoId\n        }\n    }\n\n    override fun insertInfoIfNotContains(info: CallInfo): EntityID<Int>? {\n        val count = MethodInfoTable.findRowId(info.methodInfo)?.let {\n            CallInfoTable.select {\n                CallInfoTable.methodInfoId eq it\n            }.count()\n        } ?: 0\n        if (count >= CALL_INFOS_LIMIT_FOR_PARTICULAR_METHOD) {\n            return null\n        } else {\n            return super.insertInfoIfNotContains(info)\n        }\n    }\n\n    override fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: CallInfo): Op<Boolean> {\n        return (numberOfUnnamedArguments eq info.unnamedArguments.size) and\n                (unnamedArgsTypes eq info.unnamedArgumentsTypesJoinToRawString()) and\n                (namedArgsTypes eq info.namedArgumentsJoinToRawString()) and\n                (returnType eq info.returnType)\n    }\n\n    override fun convertInfoToDependencyFormant(info: CallInfo): MethodInfo? {\n        return info.methodInfo\n    }\n\n    override fun validateInfo(info: CallInfo): Boolean {\n        return info.unnamedArgumentsTypesJoinToRawString().length <= ARGS_TYPES_STRING_LENGTH &&\n                info.returnType.length <= RETURN_TYPE_STRING_LENGTH\n    }\n\n    override fun writeInfoToBuilderNotNullableDependency(builder: UpdateBuilder<*>, info: CallInfo, dependencyId: EntityID<Int>) {\n        builder[methodInfoId] = dependencyId\n        builder[unnamedArgsTypes] = info.unnamedArgumentsTypesJoinToRawString()\n        builder[namedArgsTypes] = info.namedArgumentsJoinToRawString()\n        builder[numberOfUnnamedArguments] = info.unnamedArguments.size\n        builder[returnType] = info.returnType\n    }\n\n    override fun removeInvalidInfo(validInfo: CallInfo) {\n        val methodInfoId = MethodInfoTable.findRowId(validInfo.methodInfo) ?: return\n        deleteWhere {\n            (CallInfoTable.methodInfoId eq methodInfoId) and (CallInfoTable.numberOfUnnamedArguments neq validInfo.unnamedArguments.size)\n        }\n    }\n}\n\nclass CallInfoRow(id: EntityID<Int>) : IntEntity(id), CallInfo {\n    companion object : IntEntityClass<CallInfoRow>(CallInfoTable)\n\n    private val requiredArgsTypesRaw: String by CallInfoTable.unnamedArgsTypes\n\n    private val namedArgsTypesRaw: String by CallInfoTable.namedArgsTypes\n\n    override val namedArguments: List<ArgumentNameAndType> by lazy {\n        namedArgsTypesRaw.takeIf { it != \"\" }?.split(ARGUMENTS_TYPES_SEPARATOR)?.asSequence()?.map {\n            val (name, type) = it.split(ArgumentNameAndType.NAME_AND_TYPE_SEPARATOR)\n            return@map ArgumentNameAndType(name, type)\n        }?.toList() ?: emptyList()\n    }\n\n    override fun namedArgumentsJoinToRawString(): String = namedArgsTypesRaw\n\n    override val methodInfo: MethodInfoRow by MethodInfoRow referencedOn CallInfoTable.methodInfoId\n\n    override val unnamedArguments: List<ArgumentNameAndType> by lazy {\n        requiredArgsTypesRaw.takeIf { it != \"\" }?.split(ARGUMENTS_TYPES_SEPARATOR)?.map {\n            val (name, type) = it.split(ArgumentNameAndType.NAME_AND_TYPE_SEPARATOR)\n            return@map ArgumentNameAndType(name, type)\n        } ?: emptyList()\n    }\n\n    override val returnType: String by CallInfoTable.returnType\n\n    override fun unnamedArgumentsTypesJoinToRawString(): String = requiredArgsTypesRaw\n\n    override fun toString(): String {\n        // just for pretty debugging :)\n        return \"name: ${methodInfo.name} unnamedArguments: \" + unnamedArguments.joinToString(separator = \", \", prefix = \"[\", postfix = \"]\") +\n                \" return: $returnType\"\n    }\n\n    fun copy(): CallInfo = CallInfoImpl(methodInfo.copy(), namedArguments, unnamedArguments, returnType)\n}\n\nobject SignatureTable : IntIdTableWithDependency<SignatureInfo, MethodInfo>(MethodInfoTable) {\n    val methodInfo = reference(\"method_info\", MethodInfoTable, ReferenceOption.CASCADE).index()\n    val contract = blob(\"contract\")\n\n    override fun insertInfoIfNotContains(info: SignatureInfo): EntityID<Int>? {\n        val methodInfoRow: MethodInfoRow = MethodInfoTable.insertInfoIfNotContains(info.methodInfo)\n                ?.let { MethodInfoRow[it] } ?: return null\n\n        val existingContractData = SignatureContractRow.find { SignatureTable.methodInfo eq methodInfoRow.id }\n                .firstOrNull()\n\n        if (existingContractData != null) {\n            existingContractData.contract = info.contract\n        } else {\n            SignatureContractRow.new { this.methodInfo = methodInfoRow; contract = info.contract }\n        }\n\n        return SignatureContractRow.new { this.methodInfo = methodInfoRow; contract = info.contract }.id\n    }\n\n    override fun writeInfoToBuilderNotNullableDependency(builder: UpdateBuilder<*>, info: SignatureInfo, dependencyId: EntityID<Int>) {\n        builder[methodInfo] = dependencyId\n        builder[contract] = BlobSerializer.writeToBlob(info.contract, TransactionManager.current().connection.createBlob())\n    }\n\n    override fun SqlExpressionBuilder.createSearchCriteriaForInfo(info: SignatureInfo): Op<Boolean> {\n        return contract eq BlobSerializer.writeToBlob(info.contract, TransactionManager.current().connection.createBlob())\n    }\n\n    override fun convertInfoToDependencyFormant(info: SignatureInfo): MethodInfo {\n        return info.methodInfo\n    }\n}\n\nclass SignatureContractRow(id: EntityID<Int>) : IntEntity(id), SignatureInfo {\n    companion object : IntEntityClass<SignatureContractRow>(SignatureTable)\n\n    override var methodInfo: MethodInfoRow by MethodInfoRow referencedOn SignatureTable.methodInfo\n    override var contract: SignatureContract by BlobDeserializer()\n\n    var contractRaw: Blob by SignatureTable.contract\n\n    fun copy(): SignatureInfo = SignatureInfo(this)\n}"
  },
  {
    "path": "storage-server-api/src/main/java/org/jetbrains/ruby/codeInsight/types/storage/server/testutil/DatabaseTestUtils.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.testutil\n\nimport org.jetbrains.exposed.sql.transactions.transaction\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\n\n/**\n * This function is used to test database related things. Just creates new clean databases,\n * executes [block] and remove created databases.\n *\n * [TestCase.setUp] and [TestCase.tearDown] functions won't help because [DatabaseProvider.createAllDatabases]\n * must be called in the same [transaction] block for in memory database\n */\nfun doDBTest(block: () -> Unit) {\n    transaction {\n        DatabaseProvider.createAllDatabases()\n        block()\n        DatabaseProvider.dropAllDatabases()\n    }\n}\n"
  },
  {
    "path": "storage-server-api/src/test/java/org/jetbrains/ruby/codeInsight/types/storage/server/impl/RSignatureProviderTest.kt",
    "content": "package org.jetbrains.ruby.codeInsight.types.storage.server.impl\n\nimport junit.framework.TestCase\nimport org.jetbrains.exposed.sql.insert\nimport org.jetbrains.exposed.sql.insertAndGetId\nimport org.jetbrains.exposed.sql.transactions.TransactionManager\nimport org.jetbrains.ruby.codeInsight.types.signature.*\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.BlobSerializer\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.SignatureContract\nimport org.jetbrains.ruby.codeInsight.types.signature.serialization.StringDataInput\nimport org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider\nimport org.jetbrains.ruby.codeInsight.types.storage.server.testutil.doDBTest\nimport org.junit.Test\n\nclass RSignatureProviderTest : TestCase() {\n    init {\n        DatabaseProvider.connectToInMemoryDB(isDefaultDatabase = true)\n    }\n\n    @Test\n    fun testPutGet() = doDBTest {\n        GemInfoTable.insert { it[name] = \"rails\"; it[version] = \"5.0.0.beta1\" }\n        val insertedGem = GemInfoRow.all().first()\n        assertEquals(\"rails\", insertedGem.name)\n        assertEquals(\"5.0.0.beta1\", insertedGem.version)\n\n        ClassInfoTable.insert { it[gemInfo] = insertedGem.id; it[fqn] = \"ActiveRecord::Base\" }\n        val insertedClass = ClassInfoRow.all().first()\n        assertEquals(\"ActiveRecord::Base\", insertedClass.classFQN)\n        assertEquals(\"rails\", insertedClass.gemInfo?.name)\n\n        MethodInfoTable.insert { it[classInfo] = insertedClass.id; it[name] = \"[]=\"; it[visibility] = RVisibility.PUBLIC }\n        val insertedMethod = MethodInfoRow.all().first()\n        assertEquals(\"[]=\", insertedMethod.name)\n        assertEquals(RVisibility.PUBLIC, insertedMethod.visibility)\n        assertEquals(\"ActiveRecord::Base\", insertedMethod.classInfo.classFQN)\n    }\n\n    @Test\n    fun testClosestGem() = doDBTest {\n        val gems = listOf(\n                GemInfo(\"name1\", \"0.1\"),\n                GemInfo(\"name1\", \"0.2\"),\n                GemInfo(\"name1\", \"0.3\"),\n                GemInfo(\"name2\", \"1.0\")\n        )\n        for (gem in gems) {\n            GemInfoTable.insert { it[name] = gem.name; it[version] = gem.version }\n        }\n\n        val provider = RSignatureProviderImpl\n        assertEquals(\"0.1\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.0\"))?.version)\n        assertEquals(\"0.1\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.1\"))?.version)\n        assertEquals(\"0.1\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.1.2\"))?.version)\n        assertEquals(\"0.1\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.1.9\"))?.version)\n        assertEquals(\"0.2\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.2\"))?.version)\n        assertEquals(\"0.3\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"0.4\"))?.version)\n        assertEquals(\"0.3\", provider.getClosestRegisteredGem(GemInfo(\"name1\", \"1.0\"))?.version)\n        assertEquals(\"1.0\", provider.getClosestRegisteredGem(GemInfo(\"name2\", \"1.0\"))?.version)\n        assertEquals(\"1.0\", provider.getClosestRegisteredGem(GemInfo(\"name2\", \"0.1\"))?.version)\n        assertEquals(\"1.0\", provider.getClosestRegisteredGem(GemInfo(\"name2\", \"2.0\"))?.version)\n        assertEquals(null, provider.getClosestRegisteredGem(GemInfo(\"name3\", \"2.0\")))\n    }\n\n    @Test\n    fun testRegisteredClasses() = doDBTest {\n        val insertResult = GemInfoTable.insertAndGetId { it[name] = \"test_gem\"; it[version] = \"0.1\" }\n        ClassInfoTable.insert { it[fqn] = \"Test1\"; it[gemInfo] = insertResult }\n        ClassInfoTable.insert { it[fqn] = \"Test2\"; it[gemInfo] = insertResult }\n        ClassInfoTable.insert { it[fqn] = \"Test3\" }\n\n        val provider = RSignatureProviderImpl\n        val classes = provider.getRegisteredClasses(GemInfo(\"test_gem\", \"0.1\"))\n        assertEquals(2, classes.size)\n        assertEquals(setOf(\"Test1\", \"Test2\"), classes.map { it.classFQN }.toSet())\n    }\n\n    @Test\n    fun testRegisteredMethods() = doDBTest {\n        val gem = GemInfoTable.insertAndGetId { it[name] = \"test_gem\"; it[version] = \"1.2.3\" }\n        val class1 = ClassInfoTable.insertAndGetId { it[fqn] = \"Test::Fqn\" }\n        val class2 = ClassInfoTable.insertAndGetId { it[fqn] = \"Test2::Fqn\" }\n        val class3 = ClassInfoTable.insertAndGetId { it[fqn] = \"Test::Fqn\"; it[gemInfo] = gem }\n        MethodInfoTable.insert { it[name] = \"met1\"; it[visibility] = RVisibility.PUBLIC; it[classInfo] = class1 }\n        MethodInfoTable.insert { it[name] = \"met2\"; it[visibility] = RVisibility.PUBLIC; it[classInfo] = class1 }\n        MethodInfoTable.insert { it[name] = \"met3\"; it[visibility] = RVisibility.PUBLIC; it[classInfo] = class2 }\n        MethodInfoTable.insert { it[name] = \"met4\"; it[visibility] = RVisibility.PUBLIC; it[classInfo] = class3 }\n\n        val provider = RSignatureProviderImpl\n        val methodsWithNullGem = provider.getRegisteredMethods(ClassInfo(\"Test::Fqn\"))\n        assertEquals(2, methodsWithNullGem.size)\n        assertEquals(setOf(\"met1\", \"met2\"), methodsWithNullGem.map { it.name }.toSet())\n\n        val methodsWithGivenGem = provider.getRegisteredMethods(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"))\n        assertEquals(1, methodsWithGivenGem.size)\n        assertEquals(setOf(\"met4\"), methodsWithGivenGem.map { it.name }.toSet())\n    }\n\n    @Test\n    fun testSignatures() = doDBTest {\n        val gem = GemInfoTable.insertAndGetId { it[name] = \"test_gem\"; it[version] = \"1.2.3\" }\n        val clazz = ClassInfoTable.insertAndGetId { it[fqn] = \"Test::Fqn\"; it[gemInfo] = gem }\n        val method1 = MethodInfoTable.insertAndGetId {\n            it[name] = \"met1\"\n            it[visibility] = RVisibility.PUBLIC\n            it[classInfo] = clazz\n        }\n        val method2 = MethodInfoTable.insertAndGetId {\n            it[name] = \"met2\"\n            it[visibility] = RVisibility.PUBLIC\n            it[classInfo] = clazz\n        }\n\n        val contract1 = SignatureContract(StringDataInput(SignatureTestData.simpleContract))\n        val contract2 = SignatureContract(StringDataInput(SignatureTestData.trivialContract))\n\n        val blob1 = TransactionManager.current().connection.createBlob()\n        SignatureTable.insert { it[contract] = BlobSerializer.writeToBlob(contract1, blob1); it[methodInfo] = method1 }\n        blob1.free()\n\n        val blob2 = TransactionManager.current().connection.createBlob()\n        SignatureTable.insert { it[contract] = BlobSerializer.writeToBlob(contract2, blob2); it[methodInfo] = method2 }\n        blob2.free()\n\n        val provider = RSignatureProviderImpl\n        val signatureInfo1 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met1\", RVisibility.PUBLIC))\n        val signatureInfo2 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met2\", RVisibility.PUBLIC))\n\n        assertNotNull(signatureInfo1)\n        assertEquals(4, signatureInfo1!!.contract.nodeCount)\n\n        assertNotNull(signatureInfo2)\n        assertEquals(2, signatureInfo2!!.contract.nodeCount)\n    }\n\n    @Test\n    fun testSignaturesWithAPIPut() = doDBTest {\n        val gem = GemInfo(\"test_gem\", \"1.2.3\")\n        val clazz = ClassInfo(gem, \"Test::Fqn\")\n        val method1 = MethodInfo(clazz,\n                \"met1\",\n                RVisibility.PUBLIC)\n\n        val method2 = MethodInfo(clazz,\n                \"met2\",\n                RVisibility.PUBLIC)\n\n        val contract1 = SignatureContract(StringDataInput(SignatureTestData.simpleContract))\n        val contract2 = SignatureContract(StringDataInput(SignatureTestData.trivialContract))\n\n        val provider = RSignatureProviderImpl\n\n        provider.putSignature(SignatureInfo(method1, contract1))\n        provider.putSignature(SignatureInfo(method2, contract2))\n\n        val signatureInfo1 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met1\", RVisibility.PUBLIC))\n        val signatureInfo2 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met2\", RVisibility.PUBLIC))\n\n        assertNotNull(signatureInfo1)\n        assertEquals(4, signatureInfo1!!.contract.nodeCount)\n\n        assertNotNull(signatureInfo2)\n        assertEquals(2, signatureInfo2!!.contract.nodeCount)\n    }\n\n    @Test\n    fun testSignaturesWithSignatureReplace() = doDBTest {\n        val gem = GemInfo(\"test_gem\", \"1.2.3\")\n        val clazz = ClassInfo(gem, \"Test::Fqn\")\n        val method = MethodInfo(clazz,\n                \"met1\",\n                RVisibility.PUBLIC)\n\n        val contract1 = SignatureContract(StringDataInput(SignatureTestData.simpleContract))\n        val contract2 = SignatureContract(StringDataInput(SignatureTestData.trivialContract))\n\n        val provider = RSignatureProviderImpl\n\n        provider.putSignature(SignatureInfo(method, contract1))\n        val signatureInfo1 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met1\", RVisibility.PUBLIC))\n        assertNotNull(signatureInfo1)\n        assertEquals(4, signatureInfo1!!.contract.nodeCount)\n\n        provider.putSignature(SignatureInfo(method, contract2))\n        val signatureInfo2 = provider.getSignature(MethodInfo(ClassInfo(GemInfo(\"test_gem\", \"1.2.3\"), \"Test::Fqn\"), \"met1\", RVisibility.PUBLIC))\n        assertNotNull(signatureInfo2)\n        assertEquals(2, signatureInfo2!!.contract.nodeCount)\n    }\n\n    object SignatureTestData {\n        const val simpleContract = \"\"\"\n1 arg 0\n4\n3\n1 0 a\n2 0 b\n2 0 c\n1\n3 0 d\n1\n3 1 0\n0\n            \"\"\"\n\n        const val trivialContract = \"\"\"\n0\n2\n1\n1 0 a\n0\n\"\"\"\n\n    }\n}\n"
  }
]