aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/cmd/tools/vvet
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/cmd/tools/vvet
downloadcli-tools-windows-master.tar.gz
cli-tools-windows-master.tar.bz2
cli-tools-windows-master.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/cmd/tools/vvet')
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/array_init_one_val.out2
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/array_init_one_val.vv5
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/indent_with_space.out6
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/indent_with_space.vv24
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/module_file_test.out5
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/module_file_test.vv55
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/parens_space_a.out2
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/parens_space_a.vv4
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/parens_space_b.out2
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/parens_space_b.vv4
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/trailing_space.out7
-rw-r--r--v_windows/v/cmd/tools/vvet/tests/trailing_space.vv16
-rw-r--r--v_windows/v/cmd/tools/vvet/vet_test.v72
-rw-r--r--v_windows/v/cmd/tools/vvet/vvet.v256
14 files changed, 460 insertions, 0 deletions
diff --git a/v_windows/v/cmd/tools/vvet/tests/array_init_one_val.out b/v_windows/v/cmd/tools/vvet/tests/array_init_one_val.out
new file mode 100644
index 0000000..e10d511
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/array_init_one_val.vv b/v_windows/v/cmd/tools/vvet/tests/array_init_one_val.vv
new file mode 100644
index 0000000..2aa3514
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/indent_with_space.out b/v_windows/v/cmd/tools/vvet/tests/indent_with_space.out
new file mode 100644
index 0000000..b307e20
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/indent_with_space.vv b/v_windows/v/cmd/tools/vvet/tests/indent_with_space.vv
new file mode 100644
index 0000000..9b466ef
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/module_file_test.out b/v_windows/v/cmd/tools/vvet/tests/module_file_test.out
new file mode 100644
index 0000000..b033e71
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/module_file_test.vv b/v_windows/v/cmd/tools/vvet/tests/module_file_test.vv
new file mode 100644
index 0000000..f0f5b24
--- /dev/null
+++ b/v_windows/v/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: '// <fn name>'
+ 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/cmd/tools/vvet/tests/parens_space_a.out b/v_windows/v/cmd/tools/vvet/tests/parens_space_a.out
new file mode 100644
index 0000000..dbda99a
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/parens_space_a.vv b/v_windows/v/cmd/tools/vvet/tests/parens_space_a.vv
new file mode 100644
index 0000000..2b3b508
--- /dev/null
+++ b/v_windows/v/cmd/tools/vvet/tests/parens_space_a.vv
@@ -0,0 +1,4 @@
+fn main() {
+ _ = 1 + ( 1 + 2)
+}
+
diff --git a/v_windows/v/cmd/tools/vvet/tests/parens_space_b.out b/v_windows/v/cmd/tools/vvet/tests/parens_space_b.out
new file mode 100644
index 0000000..d1d8791
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/parens_space_b.vv b/v_windows/v/cmd/tools/vvet/tests/parens_space_b.vv
new file mode 100644
index 0000000..9ea8932
--- /dev/null
+++ b/v_windows/v/cmd/tools/vvet/tests/parens_space_b.vv
@@ -0,0 +1,4 @@
+fn main() {
+ _ = 1 + (1 + 2 )
+}
+
diff --git a/v_windows/v/cmd/tools/vvet/tests/trailing_space.out b/v_windows/v/cmd/tools/vvet/tests/trailing_space.out
new file mode 100644
index 0000000..1899a21
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/tests/trailing_space.vv b/v_windows/v/cmd/tools/vvet/tests/trailing_space.vv
new file mode 100644
index 0000000..4fe733e
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/vet_test.v b/v_windows/v/cmd/tools/vvet/vet_test.v
new file mode 100644
index 0000000..f2c8523
--- /dev/null
+++ b/v_windows/v/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/cmd/tools/vvet/vvet.v b/v_windows/v/cmd/tools/vvet/vvet.v
new file mode 100644
index 0000000..fd04b40
--- /dev/null
+++ b/v_windows/v/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
+ }
+}