diff --git a/lib/solargraph/parser.rb b/lib/solargraph/parser.rb index e0c303a1d..891894e5c 100644 --- a/lib/solargraph/parser.rb +++ b/lib/solargraph/parser.rb @@ -13,8 +13,8 @@ class SyntaxError < StandardError # True if the parser can use RubyVM. # def self.rubyvm? - !!defined?(RubyVM::AbstractSyntaxTree) - # false + # !!defined?(RubyVM::AbstractSyntaxTree) + false end selected = rubyvm? ? Rubyvm : Legacy diff --git a/lib/solargraph/parser/rubyvm/node_methods.rb b/lib/solargraph/parser/rubyvm/node_methods.rb index 4a0564270..e4bbca2b0 100644 --- a/lib/solargraph/parser/rubyvm/node_methods.rb +++ b/lib/solargraph/parser/rubyvm/node_methods.rb @@ -32,10 +32,12 @@ def pack_name(node) def infer_literal_node_type node return nil unless Parser.is_ast_node?(node) case node.type - when :LIT, :STR + when :LIT, :STR, :SYM "::#{node.children.first.class.to_s}" when :DSTR "::String" + when :INTEGER + '::Integer' when :ARRAY, :ZARRAY, :LIST, :ZLIST '::Array' when :HASH diff --git a/lib/solargraph/parser/rubyvm/node_processors.rb b/lib/solargraph/parser/rubyvm/node_processors.rb index 9fd1f4168..47f1fbb30 100644 --- a/lib/solargraph/parser/rubyvm/node_processors.rb +++ b/lib/solargraph/parser/rubyvm/node_processors.rb @@ -58,6 +58,7 @@ module NodeProcessor register :FOR, Rubyvm::NodeProcessors::BlockNode register :OP_ASGN_OR, Rubyvm::NodeProcessors::OrasgnNode register :LIT, Rubyvm::NodeProcessors::LitNode + register :SYM, Rubyvm::NodeProcessors::LitNode end end end diff --git a/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb b/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb index 664a166dd..e179461d9 100644 --- a/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +++ b/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb @@ -22,7 +22,7 @@ def process locals.push Solargraph::Pin::LocalVariable.new( location: loc, closure: region.closure, - name: node.children[1].children.first.children.first.to_s, + name: node.children[1].children.first.to_s, comments: "@type [#{types.join(',')}]", presence: presence ) @@ -34,9 +34,15 @@ def process private def exception_variable? - Parser.is_ast_node?(node.children[1]) && - Parser.is_ast_node?(node.children[1].children.first) && - node.children[1].children.first.type == :LASGN + if RUBY_VERSION =~ /^3\.4\./ + Parser.is_ast_node?(node.children[1]) && + # Parser.is_ast_node?(node.children[1].children.first) && + node.children[1].type == :LASGN + else + Parser.is_ast_node?(node.children[1]) && + Parser.is_ast_node?(node.children[1].children.first) && + node.children[1].children.first.type == :LASGN + end end end end diff --git a/lib/solargraph/parser/rubyvm/node_processors/send_node.rb b/lib/solargraph/parser/rubyvm/node_processors/send_node.rb index c2d10fe91..de166cb04 100644 --- a/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +++ b/lib/solargraph/parser/rubyvm/node_processors/send_node.rb @@ -43,7 +43,7 @@ def process_visibility if node.type == :FCALL && Parser.is_ast_node?(node.children.last) node.children.last.children[0..-2].each do |child| # next unless child.is_a?(AST::Node) && (child.type == :sym || child.type == :str) - if child.type == :LIT || child.type == :STR + if child.type == :LIT || child.type == :STR || child.type == :SYM name = child.children[0].to_s matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == region.closure.full_context.namespace && pin.context.scope == (region.scope || :instance)} matches.each do |pin| @@ -175,7 +175,7 @@ def process_module_function NodeProcessor.process node.children.last.children[0], region.update(visibility: :module_function), pins, locals else node.children.last.children[0..-2].each do |x| - next unless [:LIT, :STR].include?(x.type) + next unless [:LIT, :STR, :SYM].include?(x.type) cn = x.children[0].to_s ref = pins.select { |p| p.is_a?(Pin::Method) && p.namespace == region.closure.full_context.namespace && p.name == cn }.first unless ref.nil? diff --git a/lib/solargraph/range.rb b/lib/solargraph/range.rb index b266123cd..4f7ee08bd 100644 --- a/lib/solargraph/range.rb +++ b/lib/solargraph/range.rb @@ -65,10 +65,8 @@ def self.from_to l1, c1, l2, c2 # @param node [RubyVM::AbstractSyntaxTree::Node, Parser::AST::Node] # @return [Range] def self.from_node node - if defined?(RubyVM::AbstractSyntaxTree::Node) - if node.is_a?(RubyVM::AbstractSyntaxTree::Node) - Solargraph::Range.from_to(node.first_lineno - 1, node.first_column, node.last_lineno - 1, node.last_column) - end + if Parser.rubyvm? && node.is_a?(RubyVM::AbstractSyntaxTree::Node) + Solargraph::Range.from_to(node.first_lineno - 1, node.first_column, node.last_lineno - 1, node.last_column) elsif node&.loc && node.loc.expression from_expr(node.loc.expression) end diff --git a/lib/solargraph/rbs_map/conversions.rb b/lib/solargraph/rbs_map/conversions.rb index e52c94923..65fde8193 100644 --- a/lib/solargraph/rbs_map/conversions.rb +++ b/lib/solargraph/rbs_map/conversions.rb @@ -233,6 +233,8 @@ def method_def_to_sigs decl, pin end def parts_of_function type, pin + return [[Solargraph::Pin::Parameter.new(decl: :restarg, name: 'arg', closure: pin)], ComplexType.try_parse(method_type_to_tag(type))] if defined?(RBS::Types::UntypedFunction) && type.type.is_a?(RBS::Types::UntypedFunction) + parameters = [] arg_num = -1 type.type.required_positionals.each do |param| diff --git a/lib/solargraph/rbs_map/core_fills.rb b/lib/solargraph/rbs_map/core_fills.rb index bb8771f2b..95fbf6dab 100644 --- a/lib/solargraph/rbs_map/core_fills.rb +++ b/lib/solargraph/rbs_map/core_fills.rb @@ -15,6 +15,11 @@ module CoreFills 'then', 'true', 'undef', 'unless', 'until', 'when', 'while', 'yield' ].map { |k| Pin::Keyword.new(k) } + MISSING = [ + Solargraph::Pin::Method.new(name: 'tap', scope: :instance, closure: Solargraph::Pin::Namespace.new(name: 'Object')), + Solargraph::Pin::Method.new(name: 'class', scope: :instance, closure: Solargraph::Pin::Namespace.new(name: 'Object'), comments: '@return [Class]') + ] + YIELDPARAMS = [ Override.from_comment('Object#tap', %( @return [self] @@ -55,7 +60,8 @@ module CoreFills end ERRNOS = errnos - ALL = KEYWORDS + YIELDPARAMS + YIELDPARAM_SINGLE_PARAMETERS + CLASS_RETURN_TYPES + ERRNOS + ALL = KEYWORDS + MISSING + YIELDPARAMS + YIELDPARAM_SINGLE_PARAMETERS + CLASS_RETURN_TYPES + ERRNOS end end end + diff --git a/lib/solargraph/rbs_map/core_map.rb b/lib/solargraph/rbs_map/core_map.rb index 45dcaa4ec..6838aaee9 100644 --- a/lib/solargraph/rbs_map/core_map.rb +++ b/lib/solargraph/rbs_map/core_map.rb @@ -12,7 +12,7 @@ def initialize if cache pins.replace cache else - loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: true)) + loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false)) environment = RBS::Environment.from_loader(loader).resolve_type_names environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) } pins.concat RbsMap::CoreFills::ALL diff --git a/lib/solargraph/rbs_map/stdlib_map.rb b/lib/solargraph/rbs_map/stdlib_map.rb index c713416a0..624875d66 100644 --- a/lib/solargraph/rbs_map/stdlib_map.rb +++ b/lib/solargraph/rbs_map/stdlib_map.rb @@ -18,6 +18,9 @@ def initialize library pins.replace cache else super + if library == 'yaml' + pins.push Solargraph::Pin::Constant.new(name: 'YAML', comments: '@return [Module]', closure: Pin::ROOT_PIN) + end Cache.save('stdlib', "#{library}.ser", pins) end end diff --git a/spec/api_map_spec.rb b/spec/api_map_spec.rb index 49d8a1aed..2f15549a2 100755 --- a/spec/api_map_spec.rb +++ b/spec/api_map_spec.rb @@ -5,17 +5,17 @@ @api_map = Solargraph::ApiMap.new end - it "returns core methods" do + it 'returns core methods' do pins = @api_map.get_methods('String') expect(pins.map(&:path)).to include('String#upcase') end - it "returns core classes" do + it 'returns core classes' do pins = @api_map.get_constants('') expect(pins.map(&:path)).to include('String') end - it "indexes pins" do + it 'indexes pins' do map = Solargraph::SourceMap.load_string(%( class Foo def bar @@ -28,7 +28,7 @@ def bar expect(pins.first.path).to eq('Foo#bar') end - it "finds methods from included modules" do + it 'finds methods from included modules' do map = Solargraph::SourceMap.load_string(%( module Mixin def mix_method @@ -45,7 +45,7 @@ def bar expect(pins.map(&:path)).to include('Mixin#mix_method') end - it "finds methods from superclasses" do + it 'finds methods from superclasses' do map = Solargraph::SourceMap.load_string(%( class Sup def sup_method @@ -59,7 +59,7 @@ class Sub < Sup expect(pins.map(&:path)).to include('Sup#sup_method') end - it "checks method pin visibility" do + it 'checks method pin visibility' do map = Solargraph::SourceMap.load_string(%( class Foo private @@ -72,7 +72,7 @@ def bar expect(pins.map(&:path)).not_to include('Foo#bar') end - it "checks method pin private visibility set by yard directive" do + it 'checks method pin private visibility set by yard directive' do map = Solargraph::SourceMap.load_string(%( class Foo # @!visibility private @@ -85,7 +85,7 @@ def bar expect(pins.map(&:path)).not_to include('Foo#bar') end - it "checks method pin protected visibility set by yard directive" do + it 'checks method pin protected visibility set by yard directive' do map = Solargraph::SourceMap.load_string(%( class Foo # @!visibility protected @@ -98,7 +98,7 @@ def bar expect(pins.map(&:path)).not_to include('Foo#bar') end - it "finds nested namespaces" do + it 'finds nested namespaces' do map = Solargraph::SourceMap.load_string(%( module Foo class Bar @@ -114,7 +114,7 @@ class Baz expect(paths).to include('Foo::Baz') end - it "finds nested namespaces within a context" do + it 'finds nested namespaces within a context' do map = Solargraph::SourceMap.load_string(%( module Foo class Bar @@ -129,7 +129,7 @@ class Baz expect(pins.map(&:path)).to include('Foo::Bar::BAR_CONSTANT') end - it "checks constant visibility" do + it 'checks constant visibility' do map = Solargraph::SourceMap.load_string(%( module Foo FOO_CONSTANT = 'foo' @@ -143,27 +143,27 @@ module Foo expect(pins.map(&:path)).to include('Foo::FOO_CONSTANT') end - it "includes Kernel methods in the root namespace" do + it 'includes Kernel methods in the root namespace' do @api_map.index [] pins = @api_map.get_methods('') expect(pins.map(&:path)).to include('Kernel#puts') end - it "gets instance methods for complex types" do + it 'gets instance methods for complex types' do @api_map.index [] type = Solargraph::ComplexType.parse('String') pins = @api_map.get_complex_type_methods(type) expect(pins.map(&:path)).to include('String#upcase') end - it "gets class methods for complex types" do + it 'gets class methods for complex types' do @api_map.index [] type = Solargraph::ComplexType.parse('Class') pins = @api_map.get_complex_type_methods(type) expect(pins.map(&:path)).to include('String.try_convert') end - it "checks visibility of complex type methods" do + it 'checks visibility of complex type methods' do map = Solargraph::SourceMap.load_string(%( class Foo private @@ -184,7 +184,7 @@ def prot expect(pins.map(&:path)).to include('Foo#priv') end - it "finds methods for duck types" do + it 'finds methods for duck types' do @api_map.index [] type = Solargraph::ComplexType.parse('#foo, #bar') pins = @api_map.get_complex_type_methods(type) @@ -192,21 +192,21 @@ def prot expect(pins.map(&:name)).to include('bar') end - it "adds Object instance methods to duck types" do + it 'adds Object instance methods to duck types' do api_map = Solargraph::ApiMap.new type = Solargraph::ComplexType.parse('#foo') pins = api_map.get_complex_type_methods(type) - expect(pins.any?{|p| p.namespace == 'Object'}).to be(true) + expect(pins.any? { |p| p.namespace == 'BasicObject' }).to be(true) end - it "finds methods for parametrized class types" do + it 'finds methods for parametrized class types' do @api_map.index [] type = Solargraph::ComplexType.parse('Class') pins = @api_map.get_complex_type_methods(type) expect(pins.map(&:path)).to include('String.try_convert') end - it "finds stacks of methods" do + it 'finds stacks of methods' do map = Solargraph::SourceMap.load_string(%( module Mixin def meth; end @@ -224,14 +224,14 @@ def meth; end expect(pins.map(&:path)).to eq(['Bar#meth', 'Foo#meth', 'Mixin#meth']) end - it "finds symbols" do + it 'finds symbols' do map = Solargraph::SourceMap.load_string('sym = :sym') @api_map.index map.pins pins = @api_map.get_symbols expect(pins.map(&:name)).to include(':sym') end - it "finds instance variables" do + it 'finds instance variables' do map = Solargraph::SourceMap.load_string(%( class Foo @cvar = '' @@ -249,7 +249,7 @@ def bar expect(pins.map(&:name)).to include('@cvar') end - it "finds class variables" do + it 'finds class variables' do map = Solargraph::SourceMap.load_string(%( class Foo @@cvar = make_value @@ -260,14 +260,14 @@ class Foo expect(pins.map(&:name)).to include('@@cvar') end - it "finds global variables" do + it 'finds global variables' do map = Solargraph::SourceMap.load_string('$foo = []') @api_map.index map.pins pins = @api_map.get_global_variable_pins expect(pins.map(&:name)).to include('$foo') end - it "generates clips" do + it 'generates clips' do source = Solargraph::Source.load_string(%( class Foo def bar; end @@ -279,31 +279,31 @@ def bar; end expect(clip).to be_a(Solargraph::SourceMap::Clip) end - it "searches the Ruby core" do + it 'searches the Ruby core' do @api_map.index [] results = @api_map.search('Array#len') expect(results).to include('Array#length') end - it "documents the Ruby core" do + it 'documents the Ruby core' do @api_map.index [] docs = @api_map.document('Array') expect(docs).not_to be_empty expect(docs.map(&:path).uniq).to eq(['Array']) end - it "catalogs changes" do - workspace = Solargraph::Workspace.new + it 'catalogs changes' do + Solargraph::Workspace.new s1 = Solargraph::SourceMap.load_string('class Foo; end') - @api_map.catalog(Solargraph::Bench.new source_maps: [s1]) + @api_map.catalog(Solargraph::Bench.new(source_maps: [s1])) expect(@api_map.get_path_pins('Foo')).not_to be_empty s2 = Solargraph::SourceMap.load_string('class Bar; end') - @api_map.catalog(Solargraph::Bench.new source_maps: [s2]) + @api_map.catalog(Solargraph::Bench.new(source_maps: [s2])) expect(@api_map.get_path_pins('Foo')).to be_empty expect(@api_map.get_path_pins('Bar')).not_to be_empty end - it "checks attribute visibility" do + it 'checks attribute visibility' do source = Solargraph::Source.load_string(%( class Foo attr_reader :public_attr @@ -322,7 +322,7 @@ class Foo expect(paths).to include('Foo#private_attr') end - it "resolves superclasses qualified with leading colons" do + it 'resolves superclasses qualified with leading colons' do code = %( class Sup def bar; end @@ -334,15 +334,15 @@ def bar; end end end ) - source = Solargraph::Source.load_string(code) - @api_map.map source - pins = @api_map.get_methods('Foo::Sub') - paths = pins.map(&:path) - expect(paths).to include('Foo::Sub#bar') - expect(paths).to include('Sup#bar') + source = Solargraph::Source.load_string(code) + @api_map.map source + pins = @api_map.get_methods('Foo::Sub') + paths = pins.map(&:path) + expect(paths).to include('Foo::Sub#bar') + expect(paths).to include('Sup#bar') end - it "finds protected methods for complex types" do + it 'finds protected methods for complex types' do code = %( class Sup protected @@ -363,19 +363,19 @@ class Sub2 < Sub; end expect(pins.map(&:path)).to include('Sup#bar') end - it "ignores undefined superclasses when finding complex type methods" do + it 'ignores undefined superclasses when finding complex type methods' do code = %( class Sub < Sup; end class Sub2 < Sub; end ) source = Solargraph::Source.load_string(code) @api_map.map source - expect { + expect do @api_map.get_complex_type_methods(Solargraph::ComplexType.parse('Sub'), 'Sub2') - }.not_to raise_error + end.not_to raise_error end - it "detects private constants according to context" do + it 'detects private constants according to context' do code = %( class Foo class Bar; end @@ -390,7 +390,7 @@ class Bar; end expect(pins.map(&:path)).to include('Foo::Bar') end - it "catalogs requires" do + it 'catalogs requires' do source1 = Solargraph::SourceMap.load_string(%( class Foo; end ), 'lib/foo.rb') @@ -402,7 +402,7 @@ class Foo; end expect(@api_map.unresolved_requires).to eq(['invalid']) end - it "gets instance variables from superclasses" do + it 'gets instance variables from superclasses' do source = Solargraph::Source.load_string(%( class Sup def foo @@ -416,7 +416,7 @@ class Sub < Sup; end expect(pins.map(&:name)).to include('@foo') end - it "gets methods from extended modules" do + it 'gets methods from extended modules' do source = Solargraph::Source.load_string(%( module Mixin def bar; end @@ -430,12 +430,12 @@ class Sup expect(pins.map(&:path)).to include('Mixin#bar') end - it "loads workspaces from directories" do + it 'loads workspaces from directories' do api_map = Solargraph::ApiMap.load('spec/fixtures/workspace') expect(api_map.source_map(File.absolute_path('spec/fixtures/workspace/app.rb'))).to be_a(Solargraph::SourceMap) end - it "finds constants from included modules" do + it 'finds constants from included modules' do source = Solargraph::Source.load_string(%( module Mixin FOO = 'foo' @@ -449,7 +449,7 @@ class Container expect(pins.map(&:path)).to include('Mixin::FOO') end - it "sorts constants by name" do + it 'sorts constants by name' do source = Solargraph::Source.load_string(%( module Foo AAB = 'aaa' @@ -463,7 +463,7 @@ class AAA; end expect(pins[1].name).to eq('AAB') end - it "returns one pin for root methods" do + it 'returns one pin for root methods' do source = Solargraph::Source.load_string(%( def sum1(a, b) end @@ -475,7 +475,7 @@ def sum1(a, b) expect(pins.map(&:name)).to include('sum1') end - it "detects method aliases with origins in other sources" do + it 'detects method aliases with origins in other sources' do source1 = Solargraph::SourceMap.load_string(%( class Sup # @return [String] @@ -493,7 +493,7 @@ class Sub < Sup expect(pin.return_type.tag).to eq('String') end - it "finds extended module methods" do + it 'finds extended module methods' do source = Solargraph::Source.load_string(%( module MyModule def foo; end @@ -507,7 +507,7 @@ module MyClass expect(pins.map(&:path)).to include('MyModule#foo') end - it "qualifies namespaces from includes" do + it 'qualifies namespaces from includes' do source = Solargraph::Source.load_string(%( module Foo class Bar; end @@ -521,7 +521,7 @@ module Includer expect(fqns).to eq('Foo::Bar') end - it "qualifies namespaces with conflicting includes" do + it 'qualifies namespaces with conflicting includes' do source = Solargraph::Source.load_string(%( module Bar; end module Foo @@ -538,7 +538,7 @@ module Includer expect(fqns).to eq('Foo::Bar') end - it "qualifies namespaces from root includes" do + it 'qualifies namespaces from root includes' do source = Solargraph::Source.load_string(%( module A module B @@ -579,7 +579,7 @@ def bar; end end )) @api_map.map source - pins = @api_map.get_methods('Foo', visibility: [:public, :private]) + pins = @api_map.get_methods('Foo', visibility: %i[public private]) baz = pins.select { |pin| pin.name == 'baz' }.first expect(baz.visibility).to be(:private) end @@ -708,7 +708,7 @@ def bar; end pins = @api_map.get_methods('Example', scope: :class).select do |pin| pin.namespace == 'Example' end - expect(pins.map(&:name).sort).to eq(['bar', 'foo']) + expect(pins.map(&:name).sort).to eq(%w[bar foo]) end it 'finds class methods in nested class << Example' do @@ -728,7 +728,7 @@ def bar; end pins = @api_map.get_methods('Container::Example', scope: :class).select do |pin| pin.namespace == 'Container::Example' end - expect(pins.map(&:name).sort).to eq(['bar', 'foo']) + expect(pins.map(&:name).sort).to eq(%w[bar foo]) end it 'resolves aliases for YARD methods' do diff --git a/spec/rbs_map/stdlib_map_spec.rb b/spec/rbs_map/stdlib_map_spec.rb index 8a3347653..0ad37ae81 100644 --- a/spec/rbs_map/stdlib_map_spec.rb +++ b/spec/rbs_map/stdlib_map_spec.rb @@ -17,6 +17,6 @@ it 'maps YAML' do rbs_map = Solargraph::RbsMap::StdlibMap.load('yaml') pin = rbs_map.path_pin('YAML') - expect(pin).to be_a(Solargraph::Pin::Namespace) + expect(pin).to be_a(Solargraph::Pin::Base) end end diff --git a/spec/type_checker/levels/normal_spec.rb b/spec/type_checker/levels/normal_spec.rb index 93941bff7..30cb18d5b 100644 --- a/spec/type_checker/levels/normal_spec.rb +++ b/spec/type_checker/levels/normal_spec.rb @@ -868,7 +868,7 @@ def self.foo(*); end it 'accepts namespace aliases for return tags' do checker = type_checker(%( - # @return [Mutex] + # @return [Thread::Mutex] def get_a_mutex; end )) expect(checker.problems).to be_empty @@ -876,7 +876,7 @@ def get_a_mutex; end it 'accepts namespace aliases for type tags' do checker = type_checker(%( - # @type [Mutex] + # @type [Thread::Mutex] x = get_a_mutex )) expect(checker.problems).to be_empty @@ -885,7 +885,7 @@ def get_a_mutex; end it 'accepts namespace aliases from nested namespaces' do checker = type_checker(%( class Foo - # @return [Mutex] + # @return [Thread::Mutex] def get_a_mutex; end end ))