1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

tools: support a v vet -p file.v option that will warn about private functions with missing documentation

This commit is contained in:
Delyan Angelov 2022-04-30 16:01:35 +03:00
parent 8da42bfc85
commit c0b37409d2
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
2 changed files with 98 additions and 85 deletions

View File

@ -20,11 +20,12 @@ mut:
} }
struct Options { struct Options {
is_force bool is_force bool
is_werror bool is_werror bool
is_verbose bool is_verbose bool
show_warnings bool show_warnings bool
use_color bool use_color bool
doc_private_fns_too bool
} }
const term_colors = term.can_show_color_on_stderr() const term_colors = term.can_show_color_on_stderr()
@ -38,6 +39,7 @@ fn main() {
is_verbose: '-verbose' in vet_options || '-v' in vet_options is_verbose: '-verbose' in vet_options || '-v' in vet_options
show_warnings: '-hide-warnings' !in vet_options && '-w' !in vet_options show_warnings: '-hide-warnings' !in vet_options && '-w' !in vet_options
use_color: '-color' in vet_options || (term_colors && '-nocolor' !in vet_options) use_color: '-color' in vet_options || (term_colors && '-nocolor' !in vet_options)
doc_private_fns_too: '-p' in vet_options
} }
} }
mut paths := cmdline.only_non_options(vet_options) mut paths := cmdline.only_non_options(vet_options)
@ -110,92 +112,100 @@ fn (mut vt Vet) vet_file(path string) {
// vet_line vets the contents of `line` from `vet.file`. // vet_line vets the contents of `line` from `vet.file`.
fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) { fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) {
// Vet public functions vt.vet_fn_documentation(lines, line, lnumber)
if line.starts_with('pub fn') || (line.starts_with('fn ') && !(line.starts_with('fn C.') }
|| line.starts_with('fn main'))) {
// Scan function declarations for missing documentation // vet_fn_documentation ensures that functions are documented
is_pub_fn := line.starts_with('pub fn') fn (mut vt Vet) vet_fn_documentation(lines []string, line string, lnumber int) {
if lnumber > 0 { if line.starts_with('fn C.') {
collect_tags := fn (line string) []string { return
mut cleaned := line.all_before('/') }
cleaned = cleaned.replace_each(['[', '', ']', '', ' ', '']) is_pub_fn := line.starts_with('pub fn ')
return cleaned.split(',') is_fn := is_pub_fn || line.starts_with('fn ')
} if !is_fn {
ident_fn_name := fn (line string) string { return
mut fn_idx := line.index(' fn ') or { return '' } }
if line.len < fn_idx + 5 { if line.starts_with('fn main') {
return '' return
} }
mut tokens := line[fn_idx + 4..].split(' ') if !(is_pub_fn || vt.opt.doc_private_fns_too) {
// Skip struct identifier return
if tokens.first().starts_with('(') { }
fn_idx = line.index(')') or { return '' } // Scan function declarations for missing documentation
tokens = line[fn_idx..].split(' ') if lnumber > 0 {
if tokens.len > 1 { collect_tags := fn (line string) []string {
tokens = [tokens[1]] mut cleaned := line.all_before('/')
} cleaned = cleaned.replace_each(['[', '', ']', '', ' ', ''])
} return cleaned.split(',')
if tokens.len > 0 { }
return tokens[0].all_before('(') ident_fn_name := fn (line string) string {
} mut fn_idx := line.index(' fn ') or { return '' }
if line.len < fn_idx + 5 {
return '' return ''
} }
mut line_above := lines[lnumber - 1] mut tokens := line[fn_idx + 4..].split(' ')
mut tags := []string{} // Skip struct identifier
if !line_above.starts_with('//') { if tokens.first().starts_with('(') {
mut grab := true fn_idx = line.index(')') or { return '' }
for j := lnumber - 1; j >= 0; j-- { tokens = line[fn_idx..].split(' ')
prev_line := lines[j] if tokens.len > 1 {
if prev_line.contains('}') { // We've looked back to the above scope, stop here tokens = [tokens[1]]
break
} else if prev_line.starts_with('[') {
tags << collect_tags(prev_line)
continue
} else if prev_line.starts_with('//') { // Single-line comment
grab = false
break
}
} }
if grab { }
if tokens.len > 0 {
return tokens[0].all_before('(')
}
return ''
}
mut line_above := lines[lnumber - 1]
mut tags := []string{}
if !line_above.starts_with('//') {
mut grab := true
for j := lnumber - 1; j >= 0; j-- {
prev_line := lines[j]
if prev_line.contains('}') { // We've looked back to the above scope, stop here
break
} else if prev_line.starts_with('[') {
tags << collect_tags(prev_line)
continue
} else if prev_line.starts_with('//') { // Single-line comment
grab = false
break
}
}
if grab {
clean_line := line.all_before_last('{').trim(' ')
vt.warn('Function documentation seems to be missing for "$clean_line".',
lnumber, .doc)
}
} else {
fn_name := ident_fn_name(line)
mut grab := true
for j := lnumber - 1; j >= 0; j-- {
prev_line := lines[j]
if prev_line.contains('}') { // We've looked back to the above scope, stop here
break
} else if prev_line.starts_with('// $fn_name ') {
grab = false
break
} else if prev_line.starts_with('// $fn_name') {
grab = false
clean_line := line.all_before_last('{').trim(' ') clean_line := line.all_before_last('{').trim(' ')
if is_pub_fn { vt.warn('The documentation for "$clean_line" seems incomplete.', lnumber,
vt.warn('Function documentation seems to be missing for "$clean_line".', .doc)
lnumber, .doc) break
} } else if prev_line.starts_with('[') {
} tags << collect_tags(prev_line)
} else { continue
fn_name := ident_fn_name(line) } else if prev_line.starts_with('//') { // Single-line comment
mut grab := true continue
for j := lnumber - 1; j >= 0; j-- {
prev_line := lines[j]
if prev_line.contains('}') { // We've looked back to the above scope, stop here
break
} else if prev_line.starts_with('// $fn_name ') {
grab = false
break
} else if prev_line.starts_with('// $fn_name') {
grab = false
if is_pub_fn {
clean_line := line.all_before_last('{').trim(' ')
vt.warn('The documentation for "$clean_line" seems incomplete.',
lnumber, .doc)
}
break
} else if prev_line.starts_with('[') {
tags << collect_tags(prev_line)
continue
} else if prev_line.starts_with('//') { // Single-line comment
continue
}
}
if grab {
clean_line := line.all_before_last('{').trim(' ')
if is_pub_fn {
vt.warn('A function name is missing from the documentation of "$clean_line".',
lnumber, .doc)
}
} }
} }
if grab {
clean_line := line.all_before_last('{').trim(' ')
vt.warn('A function name is missing from the documentation of "$clean_line".',
lnumber, .doc)
}
} }
} }
} }

View File

@ -14,5 +14,8 @@ Options:
-v, -verbose -v, -verbose
Enable verbose logging. Enable verbose logging.
-p
Report private functions with missing documentation too (by default, only the `pub fn` functions will be reported).
-force -force
(NB: vet development only!) Do not skip the vet regression tests. (NB: vet development only!) Do not skip the vet regression tests.