Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/coverage/
/tmp/
dog_bench.stackprof.dump
dog_bench.pf2profile
dog_bench.json
24 changes: 1 addition & 23 deletions bin/typeprof
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,4 @@

require_relative "../lib/typeprof"

case ARGV[0]
when "--version"
puts "typeprof 0.30.0"
when "--lsp"
mode = ARGV[1]&.to_sym || :socket

core = TypeProf::Core::Service.new
begin
case mode
when :socket
TypeProf::LSP::Server.start_socket(core)
when :stdio
TypeProf::LSP::Server.start_stdio(core)
else
puts "lsp mode '#{mode}' is not supported. expected mode: socket, stdio"
end
rescue Exception
puts $!.detailed_message(highlight: false)
raise
end
else
p ARGV
end
TypeProf::CLI::CLI.new(ARGV).run
1 change: 1 addition & 0 deletions lib/typeprof.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
require_relative "typeprof/diagnostic"
require_relative "typeprof/core"
require_relative "typeprof/lsp"
require_relative "typeprof/cli"
4 changes: 4 additions & 0 deletions lib/typeprof/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "optparse"
require "pathname"

require_relative "cli/cli"
180 changes: 180 additions & 0 deletions lib/typeprof/cli/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
require "io/console"

module TypeProf::CLI
class CLI
def initialize(argv)
opt = OptionParser.new

opt.banner = "Usage: #{ opt.program_name } [options] files_or_dirs..."

core_options = {}
lsp_options = {}
cli_options = {}

output = nil
rbs_collection_path = nil

opt.separator ""
opt.separator "Options:"
opt.on("-o OUTFILE", "Output to OUTFILE instead of stdout") {|v| output = v }
opt.on("-q", "--quiet", "Quiet mode") do
core_options[:display_indicator] = false
end
opt.on("-v", "--verbose", "Verbose mode") do
core_options[:show_errors] = true
end
opt.on("--version", "Display typeprof version") { cli_options[:display_version] = true }
opt.on("--collection PATH", "File path of collection configuration") { |v| rbs_collection_path = v }
opt.on("--no-collection", "Ignore collection configuration") { rbs_collection_path = :no }
opt.on("--lsp", "LSP server mode") do |v|
core_options[:display_indicator] = false
cli_options[:lsp] = true
end

opt.separator ""
opt.separator "Analysis output options:"
opt.on("--[no-]show-typeprof-version", "Display TypeProf version in a header") {|v| core_options[:output_typeprof_version] = v }
opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| core_options[:output_diagnostics] = v }
opt.on("--[no-]show-parameter-names", "Display parameter names for methods") {|v| core_options[:output_parameter_names] = v }
opt.on("--[no-]show-source-locations", "Display definition source locations for methods") {|v| core_options[:output_source_locations] = v }

opt.separator ""
opt.separator "Advanced options:"
opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| cli_options[:stackprof] = v.to_sym }

opt.separator ""
opt.separator "LSP options:"
opt.on("--port PORT", Integer, "Specify a port number to listen for requests on") {|v| lsp_options[:port] = v }
opt.on("--stdio", "Use stdio for LSP transport") {|v| lsp_options[:stdio] = v }

opt.parse!(argv)

if cli_options[:lsp] && !lsp_options.empty?
raise OptionParser::InvalidOption.new("lsp options with non-lsp mode")
end

@core_options = {
rbs_collection: setup_rbs_collection(rbs_collection_path),
display_indicator: $stderr.tty?,
output_typeprof_version: true,
output_errors: false,
output_parameter_names: false,
output_source_locations: false,
}.merge(core_options)

@lsp_options = {
port: 0,
stdio: false,
}.merge(lsp_options)

@cli_options = {
argv:,
output: output ? open(output, "w") : $stdout.dup,
display_version: false,
stackprof: nil,
lsp: false,
}.merge(cli_options)

rescue OptionParser::InvalidOption, OptionParser::MissingArgument
puts $!
exit 1
end

def setup_rbs_collection(path)
return nil if path == :no

unless path
path = RBS::Collection::Config::PATH.exist? ? RBS::Collection::Config::PATH.to_s : nil
return nil unless path
end

if !File.readable?(path)
raise OptionParser::InvalidOption.new("file not found: #{ path }")
end

lock_path = RBS::Collection::Config.to_lockfile_path(Pathname(path))
if !File.readable?(lock_path)
raise OptionParser::InvalidOption.new("file not found: #{ lock_path.to_s }; please run 'rbs collection install")
end

RBS::Collection::Config::Lockfile.from_lockfile(lockfile_path: lock_path, data: YAML.load_file(lock_path))
end

attr_reader :core_options, :lsp_options, :cli_options

def run
core = TypeProf::Core::Service.new(@core_options)

if @cli_options[:lsp]
run_lsp(core)
else
run_cli(core)
end
end

def run_lsp(core)
if @lsp_options[:stdio]
TypeProf::LSP::Server.start_stdio(core)
else
TypeProf::LSP::Server.start_socket(core)
end
rescue Exception
puts $!.detailed_message(highlight: false).gsub(/^/, "---")
raise
end

def run_cli(core)
puts "typeprof #{ TypeProf::VERSION }" if @cli_options[:display_version]

files = find_files

set_profiler do
output = @cli_options[:output]

core.batch(files, @cli_options[:output])

output.close
end

rescue OptionParser::InvalidOption, OptionParser::MissingArgument
puts $!
exit 1
end

def find_files
files = []
@cli_options[:argv].each do |path|
if File.directory?(path)
files.concat(Dir.glob("#{ path }/**/*.{rb,rbs}"))
elsif File.file?(path)
files << path
else
raise OptionParser::InvalidOption.new("no such file or directory -- #{ path }")
end
end

if files.empty?
exit if @cli_options[:display_version]
raise OptionParser::InvalidOption.new("no input files")
end

files
end

def set_profiler
if @cli_options[:stackprof]
require "stackprof"
out = "typeprof-stackprof-#{ @cli_options[:stackprof] }.dump"
StackProf.start(mode: @cli_options[:stackprof], out: out, raw: true)
end

yield

ensure
if @cli_options[:stackprof] && defined?(StackProf)
StackProf.stop
StackProf.results
end
end
end
end
17 changes: 16 additions & 1 deletion lib/typeprof/core/graph/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ def call(changes, genv, a_args, ret)
end
end

def show
def show(output_parameter_names)
block_show = []
if @record_block.used
blk_f_args = @record_block.f_args.map {|arg| arg.show }.join(", ")
Expand Down Expand Up @@ -585,6 +585,21 @@ def show
if @f_args.rest_keywords
args << "**#{ Type.strip_parens(@f_args.rest_keywords.show) }"
end

if output_parameter_names && @node.is_a?(AST::DefNode)
names = []
names.concat(@node.req_positionals)
names.concat(@node.opt_positionals)
names.concat(@node.rest_positionals) if @node.rest_positionals
names.concat(@node.post_positionals)
names.concat(@node.req_keywords)
names.concat(@node.opt_keywords)
names.concat(@node.rest_keywords) if @node.rest_keywords
args = args.zip(names).map do |arg, name|
name ? "#{ arg } #{ name }" : arg
end
end

args = args.join(", ")
s = args.empty? ? [] : ["(#{ args })"]
s << "#{ block_show.sort.join(" | ") }" unless block_show.empty?
Expand Down
Loading
Loading