diff --git a/cmd/tools/vvet/vvet.v b/cmd/tools/vvet/vvet.v index 42bc430d07..1b9cc3f9b9 100644 --- a/cmd/tools/vvet/vvet.v +++ b/cmd/tools/vvet/vvet.v @@ -20,11 +20,12 @@ mut: } struct Options { - is_force bool - is_werror bool - is_verbose bool - show_warnings bool - use_color bool + is_force bool + is_werror bool + is_verbose bool + show_warnings bool + use_color bool + doc_private_fns_too bool } 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 show_warnings: '-hide-warnings' !in vet_options && '-w' !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) @@ -110,92 +112,100 @@ fn (mut vt Vet) vet_file(path string) { // vet_line vets the contents of `line` from `vet.file`. fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) { - // Vet public functions - 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 - is_pub_fn := line.starts_with('pub fn') - if lnumber > 0 { - collect_tags := fn (line string) []string { - mut cleaned := line.all_before('/') - cleaned = cleaned.replace_each(['[', '', ']', '', ' ', '']) - return cleaned.split(',') - } - ident_fn_name := fn (line string) string { - mut fn_idx := line.index(' fn ') or { return '' } - if line.len < fn_idx + 5 { - return '' - } - mut tokens := line[fn_idx + 4..].split(' ') - // Skip struct identifier - if tokens.first().starts_with('(') { - fn_idx = line.index(')') or { return '' } - tokens = line[fn_idx..].split(' ') - if tokens.len > 1 { - tokens = [tokens[1]] - } - } - if tokens.len > 0 { - return tokens[0].all_before('(') - } + vt.vet_fn_documentation(lines, line, lnumber) +} + +// vet_fn_documentation ensures that functions are documented +fn (mut vt Vet) vet_fn_documentation(lines []string, line string, lnumber int) { + if line.starts_with('fn C.') { + return + } + is_pub_fn := line.starts_with('pub fn ') + is_fn := is_pub_fn || line.starts_with('fn ') + if !is_fn { + return + } + if line.starts_with('fn main') { + return + } + if !(is_pub_fn || vt.opt.doc_private_fns_too) { + return + } + // Scan function declarations for missing documentation + if lnumber > 0 { + collect_tags := fn (line string) []string { + mut cleaned := line.all_before('/') + cleaned = cleaned.replace_each(['[', '', ']', '', ' ', '']) + return cleaned.split(',') + } + ident_fn_name := fn (line string) string { + mut fn_idx := line.index(' fn ') or { return '' } + if line.len < fn_idx + 5 { 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 - } + mut tokens := line[fn_idx + 4..].split(' ') + // Skip struct identifier + if tokens.first().starts_with('(') { + fn_idx = line.index(')') or { return '' } + tokens = line[fn_idx..].split(' ') + if tokens.len > 1 { + tokens = [tokens[1]] } - 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(' ') - if is_pub_fn { - 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 - 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) - } + 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(' ') + vt.warn('A function name is missing from the documentation of "$clean_line".', + lnumber, .doc) + } } } } diff --git a/cmd/v/help/vet.txt b/cmd/v/help/vet.txt index 7a0d2bf33f..a996b17811 100644 --- a/cmd/v/help/vet.txt +++ b/cmd/v/help/vet.txt @@ -14,5 +14,8 @@ Options: -v, -verbose Enable verbose logging. + -p + Report private functions with missing documentation too (by default, only the `pub fn` functions will be reported). + -force (NB: vet development only!) Do not skip the vet regression tests.