From f5c4671bfbad96bf346bd7e9a21fc4317b4959df Mon Sep 17 00:00:00 2001 From: Indrajith K L Date: Sat, 3 Dec 2022 17:00:20 +0530 Subject: Adds most of the tools --- .../cmd/tools/vvet/tests/array_init_one_val.out | 2 + .../old/cmd/tools/vvet/tests/array_init_one_val.vv | 5 + .../old/cmd/tools/vvet/tests/indent_with_space.out | 6 + .../old/cmd/tools/vvet/tests/indent_with_space.vv | 24 ++ .../old/cmd/tools/vvet/tests/module_file_test.out | 5 + .../v/old/cmd/tools/vvet/tests/module_file_test.vv | 55 +++++ .../v/old/cmd/tools/vvet/tests/parens_space_a.out | 2 + .../v/old/cmd/tools/vvet/tests/parens_space_a.vv | 4 + .../v/old/cmd/tools/vvet/tests/parens_space_b.out | 2 + .../v/old/cmd/tools/vvet/tests/parens_space_b.vv | 4 + .../v/old/cmd/tools/vvet/tests/trailing_space.out | 7 + .../v/old/cmd/tools/vvet/tests/trailing_space.vv | 16 ++ v_windows/v/old/cmd/tools/vvet/vet_test.v | 72 ++++++ v_windows/v/old/cmd/tools/vvet/vvet.v | 256 +++++++++++++++++++++ 14 files changed, 460 insertions(+) create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/module_file_test.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/module_file_test.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/trailing_space.out create mode 100644 v_windows/v/old/cmd/tools/vvet/tests/trailing_space.vv create mode 100644 v_windows/v/old/cmd/tools/vvet/vet_test.v create mode 100644 v_windows/v/old/cmd/tools/vvet/vvet.v (limited to 'v_windows/v/old/cmd/tools/vvet') diff --git a/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.out b/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.out new file mode 100644 index 0000000..e10d511 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.out @@ -0,0 +1,2 @@ +cmd/tools/vvet/tests/array_init_one_val.vv:2: error: Use `var == value` instead of `var in [value]` +NB: You can run `v fmt -w file.v` to fix these errors automatically diff --git a/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.vv b/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.vv new file mode 100644 index 0000000..2aa3514 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/array_init_one_val.vv @@ -0,0 +1,5 @@ +fn main() { + if 1 in [1] { + println('hello world') + } +} diff --git a/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.out b/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.out new file mode 100644 index 0000000..b307e20 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.out @@ -0,0 +1,6 @@ +cmd/tools/vvet/tests/indent_with_space.vv:2: error: Looks like you are using spaces for indentation. +cmd/tools/vvet/tests/indent_with_space.vv:10: error: Looks like you are using spaces for indentation. +cmd/tools/vvet/tests/indent_with_space.vv:17: error: Looks like you are using spaces for indentation. +cmd/tools/vvet/tests/indent_with_space.vv:20: error: Looks like you are using spaces for indentation. +cmd/tools/vvet/tests/indent_with_space.vv:22: error: Looks like you are using spaces for indentation. +NB: You can run `v fmt -w file.v` to fix these errors automatically diff --git a/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.vv b/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.vv new file mode 100644 index 0000000..9b466ef --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/indent_with_space.vv @@ -0,0 +1,24 @@ +fn main() { + _ = 1 == 2 +} + +fn block_comments() { + /* tab to indent the comment + spaces before + also spaces before + same here */ + /* spaces for comment indentation (ouch) + and inside too + */ +} + +fn space_inside_strings() { + // Plain strings + str := "Bad space usage for variable indentation. + Here it's fine. + Here too." + str2 := 'linebreak and space\n inside' + // String interpolation + si1 := 'Error here $foo + and not here' +} diff --git a/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.out b/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.out new file mode 100644 index 0000000..b033e71 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.out @@ -0,0 +1,5 @@ +cmd/tools/vvet/tests/module_file_test.vv:7: warning: Function documentation seems to be missing for "pub fn foo() string". +cmd/tools/vvet/tests/module_file_test.vv:13: warning: A function name is missing from the documentation of "pub fn bar() string". +cmd/tools/vvet/tests/module_file_test.vv:35: warning: Function documentation seems to be missing for "pub fn (f Foo) foo() string". +cmd/tools/vvet/tests/module_file_test.vv:46: warning: A function name is missing from the documentation of "pub fn (f Foo) fooo() string". +cmd/tools/vvet/tests/module_file_test.vv:52: warning: The documentation for "pub fn (f Foo) boo() string" seems incomplete. \ No newline at end of file diff --git a/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.vv b/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.vv new file mode 100644 index 0000000..f0f5b24 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/module_file_test.vv @@ -0,0 +1,55 @@ +module foo + +struct Foo { + foo int +} + +pub fn foo() string { + // Missing doc + return 'foo' +} + +// foo does bar +pub fn bar() string { + // not using convention style: '// ' + return 'bar' +} + +// fooo does x +pub fn fooo() string { + // Documented + return 'fooo' +} + +// booo does x +fn booo() string { + // Documented, but not pub + return 'booo' +} + +fn boo() string { + // Missing doc + return 'boo' +} + +pub fn (f Foo) foo() string { + // Missing doc + return f.fo() +} + +fn (f Foo) fo() string { + // Missing doc, but not pub + return 'foo' +} + +// wrong doc +pub fn (f Foo) fooo() string { + // not using convention + return f.fo() +} + +// boo +pub fn (f Foo) boo() string { + // Incomplete doc + return f.fo() +} diff --git a/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.out b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.out new file mode 100644 index 0000000..dbda99a --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.out @@ -0,0 +1,2 @@ +cmd/tools/vvet/tests/parens_space_a.vv:1: error: Looks like you are adding a space after `(` +NB: You can run `v fmt -w file.v` to fix these errors automatically diff --git a/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.vv b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.vv new file mode 100644 index 0000000..2b3b508 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_a.vv @@ -0,0 +1,4 @@ +fn main() { + _ = 1 + ( 1 + 2) +} + diff --git a/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.out b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.out new file mode 100644 index 0000000..d1d8791 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.out @@ -0,0 +1,2 @@ +cmd/tools/vvet/tests/parens_space_b.vv:1: error: Looks like you are adding a space before `)` +NB: You can run `v fmt -w file.v` to fix these errors automatically diff --git a/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.vv b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.vv new file mode 100644 index 0000000..9ea8932 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/parens_space_b.vv @@ -0,0 +1,4 @@ +fn main() { + _ = 1 + (1 + 2 ) +} + diff --git a/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.out b/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.out new file mode 100644 index 0000000..1899a21 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.out @@ -0,0 +1,7 @@ +cmd/tools/vvet/tests/trailing_space.vv:5: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:6: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:7: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:8: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:9: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:13: error: Looks like you have trailing whitespace. +cmd/tools/vvet/tests/trailing_space.vv:15: error: Looks like you have trailing whitespace. diff --git a/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.vv b/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.vv new file mode 100644 index 0000000..4fe733e --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/tests/trailing_space.vv @@ -0,0 +1,16 @@ +// NB: This file has and *should* have trailing spaces. +// When making changes, please ensure they are not removed. + +fn after_comments() { + // spaces after line comments give errors + /* + in block comments + too + */ +} + +fn main() { + var := 'error about the spaces right there' + no_err := "inside multi line strings it's fine. +but not after" +} diff --git a/v_windows/v/old/cmd/tools/vvet/vet_test.v b/v_windows/v/old/cmd/tools/vvet/vet_test.v new file mode 100644 index 0000000..3291f20 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/vet_test.v @@ -0,0 +1,72 @@ +import os +import rand +import term +import v.util.vtest +import v.util.diff + +const diff_cmd = find_diff_cmd() + +fn find_diff_cmd() string { + res := diff.find_working_diff_command() or { '' } + return res +} + +fn test_vet() { + vexe := os.getenv('VEXE') + vroot := os.dir(vexe) + os.chdir(vroot) + test_dir := 'cmd/tools/vvet/tests' + tests := get_tests_in_dir(test_dir) + fails := check_path(vexe, test_dir, tests) + assert fails == 0 +} + +fn get_tests_in_dir(dir string) []string { + files := os.ls(dir) or { panic(err) } + mut tests := files.filter(it.ends_with('.vv')) + tests.sort() + return tests +} + +fn check_path(vexe string, dir string, tests []string) int { + mut nb_fail := 0 + paths := vtest.filter_vtest_only(tests, basepath: dir) + for path in paths { + program := path + print(path + ' ') + // -force is needed so that `v vet` would not skip the regression files + res := os.execute('$vexe vet -force -nocolor $program') + if res.exit_code < 0 { + panic(res.output) + } + mut expected := os.read_file(program.replace('.vv', '') + '.out') or { panic(err) } + expected = clean_line_endings(expected) + found := clean_line_endings(res.output) + if expected != found { + println(term.red('FAIL')) + println('============') + println('expected:') + println(expected) + println('============') + println('found:') + println(found) + println('============\n') + println('diff:') + println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected)) + println('============\n') + nb_fail++ + } else { + println(term.green('OK')) + } + } + return nb_fail +} + +fn clean_line_endings(s string) string { + mut res := s.trim_space() + res = res.replace(' \n', '\n') + res = res.replace(' \r\n', '\n') + res = res.replace('\r\n', '\n') + res = res.trim('\n') + return res +} diff --git a/v_windows/v/old/cmd/tools/vvet/vvet.v b/v_windows/v/old/cmd/tools/vvet/vvet.v new file mode 100644 index 0000000..fd04b40 --- /dev/null +++ b/v_windows/v/old/cmd/tools/vvet/vvet.v @@ -0,0 +1,256 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module main + +import os +import os.cmdline +import v.vet +import v.pref +import v.parser +import v.token +import v.ast +import term + +struct Vet { + opt Options +mut: + errors []vet.Error + warns []vet.Error + file string +} + +struct Options { + is_force bool + is_werror bool + is_verbose bool + show_warnings bool + use_color bool +} + +const term_colors = term.can_show_color_on_stderr() + +fn main() { + vet_options := cmdline.options_after(os.args, ['vet']) + mut vt := Vet{ + opt: Options{ + is_force: '-force' in vet_options + is_werror: '-W' in vet_options + 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) + } + } + mut paths := cmdline.only_non_options(vet_options) + vtmp := os.getenv('VTMP') + if vtmp != '' { + // `v test-cleancode` passes also `-o tmpfolder` as well as all options in VFLAGS + paths = paths.filter(!it.starts_with(vtmp)) + } + for path in paths { + if !os.exists(path) { + eprintln('File/folder $path does not exist') + continue + } + if os.is_file(path) { + vt.vet_file(path) + } + if os.is_dir(path) { + vt.vprintln("vetting folder: '$path' ...") + vfiles := os.walk_ext(path, '.v') + vvfiles := os.walk_ext(path, '.vv') + mut files := []string{} + files << vfiles + files << vvfiles + for file in files { + vt.vet_file(file) + } + } + } + vfmt_err_count := vt.errors.filter(it.fix == .vfmt).len + if vt.opt.show_warnings { + for w in vt.warns { + eprintln(vt.e2string(w)) + } + } + for err in vt.errors { + eprintln(vt.e2string(err)) + } + if vfmt_err_count > 0 { + eprintln('NB: You can run `v fmt -w file.v` to fix these errors automatically') + } + if vt.errors.len > 0 { + exit(1) + } +} + +// vet_file vets the file read from `path`. +fn (mut vt Vet) vet_file(path string) { + if path.contains('/tests/') && !vt.opt.is_force { + // skip all /tests/ files, since usually their content is not + // important enough to be documented/vetted, and they may even + // contain intentionally invalid code. + vt.vprintln("skipping test file: '$path' ...") + return + } + vt.file = path + mut prefs := pref.new_preferences() + prefs.is_vet = true + prefs.is_vsh = path.ends_with('.vsh') + table := ast.new_table() + vt.vprintln("vetting file '$path'...") + _, errors := parser.parse_vet_file(path, table, prefs) + // Transfer errors from scanner and parser + vt.errors << errors + // Scan each line in file for things to improve + source_lines := os.read_lines(vt.file) or { []string{} } + for lnumber, line in source_lines { + vt.vet_line(source_lines, line, lnumber) + } +} + +// 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('(') + } + 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(' ') + 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) + } + } + } + } + } +} + +fn (vt &Vet) vprintln(s string) { + if !vt.opt.is_verbose { + return + } + println(s) +} + +fn (vt &Vet) e2string(err vet.Error) string { + mut kind := '$err.kind:' + mut location := '$err.file_path:$err.pos.line_nr:' + if vt.opt.use_color { + kind = match err.kind { + .warning { term.magenta(kind) } + .error { term.red(kind) } + } + kind = term.bold(kind) + location = term.bold(location) + } + return '$location $kind $err.message' +} + +fn (mut vt Vet) error(msg string, line int, fix vet.FixKind) { + pos := token.Position{ + line_nr: line + 1 + } + vt.errors << vet.Error{ + message: msg + file_path: vt.file + pos: pos + kind: .error + fix: fix + typ: .default + } +} + +fn (mut vt Vet) warn(msg string, line int, fix vet.FixKind) { + pos := token.Position{ + line_nr: line + 1 + } + mut w := vet.Error{ + message: msg + file_path: vt.file + pos: pos + kind: .warning + fix: fix + typ: .default + } + if vt.opt.is_werror { + w.kind = .error + vt.errors << w + } else { + vt.warns << w + } +} -- cgit v1.2.3