Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn if parameters that don't exist are documented #20

Merged
merged 1 commit into from
Oct 2, 2020
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
88 changes: 55 additions & 33 deletions lib/puppet-lint/plugins/check_parameter_documentation.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
PuppetLint.new_check(:parameter_documentation) do
def check
class_indexes.concat(defined_type_indexes).each do |idx|
next if idx[:param_tokens].nil?

doc_params = {}
doc_params_duplicates = Hash.new { |hash, key| hash[key] = [doc_params[key]] }
is_private = false
Expand All @@ -25,51 +23,75 @@ def check
end
end

next if is_private

params = []
e = idx[:param_tokens].each
begin
while (ptok = e.next)
if ptok.type == :VARIABLE
params << ptok
nesting = 0
# skip to the next parameter to avoid finding default values of variables
while true
ptok = e.next
case ptok.type
when :LPAREN
nesting += 1
when :RPAREN
nesting -= 1
when :COMMA
break unless nesting > 0
end
end
end
end
rescue StopIteration; end
params = extract_params(idx)

# warn about duplicates
doc_params_duplicates.each do |parameter, tokens|
tokens.each do |token|
notify :warning, {
:message => "Duplicate parameter documentation for #{parameter}",
:message => "Duplicate #{type_str(idx)} parameter documentation for #{parameter}",
:line => token.line,
:column => token.column + token.value.match(/\A\s*(@param\s*)?/)[0].length + 1 # `+ 1` is to account for length of the `#` COMMENT token.
}
end
end

params.each do |p|
next if doc_params.has_key? p.value
idx_type = idx[:type] == :CLASS ? "class" : "defined type"
# warn about documentation for parameters that don't exist
doc_params.each do |parameter, token|
next if params.find { |p| p.value == parameter }

notify :warning, {
:message => "missing documentation for #{idx_type} parameter #{idx[:name_token].value}::#{p.value}",
:line => p.line,
:column => p.column,
:message => "No matching #{type_str(idx)} parameter for documentation of #{parameter}",
:line => token.line,
:column => token.column + token.value.match(/\A\s*(@param\s*)?/)[0].length + 1
}
end

unless is_private
params.each do |p|
next if doc_params.has_key? p.value
notify :warning, {
:message => "missing documentation for #{type_str(idx)} parameter #{idx[:name_token].value}::#{p.value}",
:line => p.line,
:column => p.column,
}
end
end
end
end

private

def type_str(idx)
idx[:type] == :CLASS ? "class" : "defined type"
end

def extract_params(idx)
params = []
return params if idx[:param_tokens].nil?

e = idx[:param_tokens].each
begin
while (ptok = e.next)
if ptok.type == :VARIABLE
params << ptok
nesting = 0
# skip to the next parameter to avoid finding default values of variables
while true
ptok = e.next
case ptok.type
when :LPAREN
nesting += 1
when :RPAREN
nesting -= 1
ekohl marked this conversation as resolved.
Show resolved Hide resolved
when :COMMA
break unless nesting > 0
end
end
end
end
rescue StopIteration; end

params
end
end
104 changes: 97 additions & 7 deletions spec/puppet-lint/plugins/check_parameter_documentation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -564,11 +564,11 @@ class example($foo, $bar) { }
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(3).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(3).in_column(10)
end

it 'should create a warning on line 6' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(6).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(6).in_column(10)
end
end

Expand All @@ -594,15 +594,41 @@ class example($foo, $bar) { }
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(3).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(3).in_column(10)
end

it 'should create a warning on line 6' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(6).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(6).in_column(10)
end

it 'should create a warning on line 8' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(8).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(8).in_column(10)
end
end

context 'private class with parameters documented twice (@param)' do
let(:code) do
<<-EOS.gsub(/^\s+/, '')
# @summary Example class
#
# @param bar docs
# @param bar Duplicate/conflicting docs
#
# @api private
class example($bar) { }
EOS
end

it 'should detect two problems' do
expect(problems).to have(2).problem
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(3).in_column(10)
end

it 'should create a warning on line 4' do
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(4).in_column(10)
end
end

Expand All @@ -625,11 +651,75 @@ class example($foo, $bar) { }
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(3).in_column(10)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(3).in_column(10)
end

it 'should create a warning on line 6' do
expect(problems).to contain_warning('Duplicate parameter documentation for bar').on_line(6).in_column(3)
expect(problems).to contain_warning('Duplicate class parameter documentation for bar').on_line(6).in_column(3)
end
end

context 'class with documentation for parameters that don\'t exist' do
let(:code) do
<<-EOS.gsub(/^\s+/, '')
# @summary Example class
#
# @param foo
class example { }
EOS
end

it 'should detect a single problem' do
expect(problems).to have(1).problem
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('No matching class parameter for documentation of foo').on_line(3).in_column(10)
end
end

context 'private class with documentation for parameters that don\'t exist' do
let(:code) do
<<-EOS.gsub(/^\s+/, '')
# @summary Example class
#
# @param foo
# Example docs
#
# @api private
class example { }
EOS
end

it 'should detect a single problem' do
expect(problems).to have(1).problem
end

it 'should create a warning on line 3' do
expect(problems).to contain_warning('No matching class parameter for documentation of foo').on_line(3).in_column(10)
end
end

context 'define with documentation for parameters that don\'t exist' do
let(:code) do
<<-EOS.gsub(/^\s+/, '')
# @summary Example define
#
# @param bar Docs for bar
# @param foo
# Docs for foo
#
# @api private
define example::example(String[1] $bar) { }
EOS
end

it 'should detect a single problem' do
expect(problems).to have(1).problem
end

it 'should create a warning on line 4' do
expect(problems).to contain_warning('No matching defined type parameter for documentation of foo').on_line(4).in_column(10)
end
end
end