Skip to content

Commit

Permalink
Don't require redundant attribute @return and @param tags
Browse files Browse the repository at this point in the history
If the underlying instance variable is already typed (either via @type
or via creation from a typed initializer param), don't require
attributes (e.g., attr_accessor, attr_reader, etc.) to have redundant
@return and @param tags, even under strong typechecking.
  • Loading branch information
apiology committed Feb 20, 2025
1 parent b28078e commit 5674fa2
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
16 changes: 14 additions & 2 deletions lib/solargraph/type_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ def method_return_type_problems_for pin
declared = pin.typify(api_map).self_to(pin.full_context.namespace)
if declared.undefined?
if pin.return_type.undefined? && rules.require_type_tags?
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
if pin.attribute?
inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
else
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
end
elsif pin.return_type.defined? && !resolved_constant?(pin)
result.push Problem.new(pin.location, "Unresolved return type #{pin.return_type} for #{pin.path}", pin: pin)
elsif rules.must_tag_or_infer? && pin.probe(api_map).undefined?
Expand Down Expand Up @@ -141,7 +146,14 @@ def method_param_type_problems_for pin
sig.parameters.each do |par|
break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
unless params[par.name]
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
if pin.attribute?
inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
if inferred.undefined?
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
end
else
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
end
end
end
end
Expand Down
55 changes: 55 additions & 0 deletions spec/type_checker/levels/strong_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,61 @@ def bar baz
expect(checker.problems.first.message).to include('Missing @param tag')
end

it 'reports missing param and return tags on writers when instance variable type not defined' do
checker = type_checker(%(
class Foo
attr_writer :bar
end
))
expect(checker.problems.map(&:message)).to include('Missing @param tag for value on Foo#bar=')
expect(checker.problems.map(&:message)).to include('Missing @return tag for Foo#bar=')
end

it 'reports missing return tags on readers when instance variable type not defined' do
checker = type_checker(%(
class Foo
attr_reader :bar
end
))
expect(checker.problems).to be_one
expect(checker.problems.first.message).to include('Missing @return tag')
end

it 'ignores missing return tags on readers when instance variable type not defined' do
checker = type_checker(%(
class Foo
# @param bar [String]
def initialize(bar)
@bar = bar
end
attr_reader :bar
end
))
expect(checker.problems.map(&:message)).to be_empty
end

it 'ignores missing param and return tags on writers when instance variable type defined' do
checker = type_checker(%(
class Foo
# @param bar [String]
def initialize(bar)
@bar = bar
end
attr_writer :bar
end
class Bar
# @param baz [String]
def initialize(baz)
@baz = baz
end
end
))
expect(checker.problems.map(&:message)).to be_empty
end

it 'reports missing kwoptarg param tags' do
checker = type_checker(%(
class Foo
Expand Down

0 comments on commit 5674fa2

Please sign in to comment.