Repository: Konstantin8105/c4go
Pull request #480 (2020-02-15 13:46:36)

unused flag

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=h1) Report
> Merging [#480](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/2be694ee034469afcdb348d84c551e7c61d025bd?src=pr&el=desc) will **decrease** coverage by `0.42%`.
> The diff coverage is `0%`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/480/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##           master    #480      +/-   ##
=========================================
- Coverage   84.72%   84.3%   -0.43%     
=========================================
  Files         192     193       +1     
  Lines       12069   12130      +61     
=========================================
  Hits        10226   10226              
- Misses       1341    1402      +61     
  Partials      502     502
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [unused.go](https://codecov.io/gh/Konstantin8105/c4go/pull/480/diff?src=pr&el=tree#diff-dW51c2VkLmdv) | `0% <0%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=footer). Last update [2be694e...7deda34](https://codecov.io/gh/Konstantin8105/c4go/pull/480?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/main.go b/main.go
index 9707b47..f6918f4 100644
--- a/main.go
+++ b/main.go
@@ -597,6 +597,11 @@ func runCommand() int {
 			"p", "debug.", "prefix of output C filename with addition debug information")
 		debugHelpFlag = debugCommand.Bool(
 			"h", false, "print help information")
+
+		unusedCommand = flag.NewFlagSet(
+			"unused", flag.ContinueOnError)
+		unusedHelpFlag = unusedCommand.Bool(
+			"h", false, "print help information")
 	)
 	var clangFlags inputDataFlags
 	transpileCommand.Var(&clangFlags,
@@ -618,6 +623,7 @@ func runCommand() int {
 		usage += "  ast\t\tprint AST before translated Go code\n"
 		usage += "  debug\t\tadd debug information in C source\n"
 		usage += "  version\tprint version of c4go\n"
+		usage += "  unused\tshow and action for unused functions\n"
 		usage += "\n"
 		fmt.Fprintf(stderr, usage, os.Args[0])
 
@@ -627,6 +633,7 @@ func runCommand() int {
 	transpileCommand.SetOutput(stderr)
 	astCommand.SetOutput(stderr)
 	debugCommand.SetOutput(stderr)
+	unusedCommand.SetOutput(stderr)
 
 	flag.Parse()
 
@@ -712,6 +719,21 @@ func runCommand() int {
 		args.clangFlags = clangFlags
 		args.cppCode = *debugCppFlag
 
+	case "unused":
+		err := unusedCommand.Parse(os.Args[2:])
+		if err != nil {
+			fmt.Fprintf(os.Stdout, "unused command cannot parse: %v", err)
+			return 12
+		}
+
+		if *unusedHelpFlag || unusedCommand.NArg() == 0 {
+			unusedCommand.PrintDefaults()
+			return 32
+		}
+
+		unused(unusedCommand.Args()...)
+		return 0
+
 	case "version":
 		fmt.Fprint(stderr, version.Version())
 		return 0
diff --git a/unused.go b/unused.go
new file mode 100644
index 0000000..9361c28
--- /dev/null
+++ b/unused.go
@@ -0,0 +1,128 @@
+package main
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"os"
+	"sort"
+)
+
+func unused(filenames ...string) {
+	for _, src := range filenames {
+		fset := token.NewFileSet() // positions are relative to fset
+
+		// Parse src but stop after processing the imports.
+		f, err := parser.ParseFile(fset, src, nil, parser.ParseComments)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%v", err)
+			return
+		}
+
+		// map
+		m := map[string][]string{}
+
+		// Print the imports from the file's AST.
+		for i := range f.Decls {
+			decls := f.Decls[i]
+			if fd, ok := decls.(*ast.FuncDecl); ok {
+				name := fd.Name.Name
+				var cs CallSearcher
+				ast.Walk(&cs, fd)
+				m[name] = cs.used
+			}
+		}
+
+		// list of all function
+		used := map[string]bool{}
+		list := []string{"main"}
+
+		for iter := len(m) * 10; iter > 0; iter-- {
+		rem:
+			sort.Strings(list)
+			for i := range list {
+				if i == 0 {
+					continue
+				}
+				if list[i-1] == list[i] {
+					// remove from list
+					list = append(list[:i], list[i+1:]...)
+					goto rem
+				}
+			}
+			for i := range list {
+				_, ok := used[list[i]]
+				if ok {
+					// remove from list
+					list = append(list[:i], list[i+1:]...)
+					goto rem
+				}
+			}
+			var newlist []string
+			for k, v := range m {
+				for i := range list {
+					used[list[i]] = true
+					if k == list[i] {
+						used[k] = true
+						newlist = append(newlist, v...)
+					}
+				}
+			}
+			list = newlist
+		}
+
+		// full list
+		full := map[string]bool{}
+		for k, v := range m {
+			full[k] = true
+			for i := range v {
+				full[v[i]] = true
+			}
+		}
+
+		// unused
+		for k := range full {
+			_, ok := used[k]
+			if ok {
+				continue
+			}
+			fmt.Fprintf(os.Stdout, "%s\n", k)
+		}
+	}
+}
+
+type CallSearcher struct {
+	used []string
+}
+
+var GoFuncs = []string{
+	"len", "make", "append",
+	"string",
+	"float64", "float32",
+	"int", "int64", "int32", "int16",
+	"go", "close",
+	"panic",
+}
+
+func (c *CallSearcher) Visit(node ast.Node) (w ast.Visitor) {
+	if call, ok := node.(*ast.CallExpr); ok {
+		if f, ok := call.Fun.(*ast.Ident); ok {
+			isFound := false
+			for i := range GoFuncs {
+				if f.Name == GoFuncs[i] {
+					isFound = true
+				}
+			}
+			if !isFound {
+				c.used = append(c.used, f.Name)
+			}
+		}
+	}
+	return c
+}
+
+func search(f *ast.FuncDecl) (used []string) {
+
+	return
+}
diff --git a/vendor/github.com/pkg/term/termios/pty_freebsd.go b/vendor/github.com/pkg/term/termios/pty_freebsd.go
index e4b933a..f71e3d3 100644
--- a/vendor/github.com/pkg/term/termios/pty_freebsd.go
+++ b/vendor/github.com/pkg/term/termios/pty_freebsd.go
@@ -17,7 +17,7 @@ func posix_openpt(oflag int) (fd uintptr, err error) {
 }
 
 func open_pty_master() (uintptr, error) {
-	return posix_openpt(syscall.O_NOCTTY|syscall.O_RDWR|syscall.O_CLOEXEC)
+	return posix_openpt(syscall.O_NOCTTY | syscall.O_RDWR | syscall.O_CLOEXEC)
 }
 
 func Ptsname(fd uintptr) (string, error) {
diff --git a/vendor/github.com/pkg/term/termios/termios_solaris.go b/vendor/github.com/pkg/term/termios/termios_solaris.go
index 1c6e694..c9a9eb4 100644
--- a/vendor/github.com/pkg/term/termios/termios_solaris.go
+++ b/vendor/github.com/pkg/term/termios/termios_solaris.go
@@ -101,27 +101,26 @@ func Cfsetospeed(attr *syscall.Termios, speed uintptr) error {
 	return err
 }
 
-
 // tiosToUnix copies a syscall.Termios to a x/sys/unix.Termios.
 // This is needed since type conversions between the two fail due to
 // more recent x/sys/unix.Termios renaming the padding field.
 func tiosToUnix(st *syscall.Termios) *unix.Termios {
 	return &unix.Termios{
-		Iflag:  st.Iflag,
-		Oflag:  st.Oflag,
-		Cflag:  st.Cflag,
-		Lflag:  st.Lflag,
-		Cc:     st.Cc,
+		Iflag: st.Iflag,
+		Oflag: st.Oflag,
+		Cflag: st.Cflag,
+		Lflag: st.Lflag,
+		Cc:    st.Cc,
 	}
 }
 
 // tiosToSyscall copies a x/sys/unix.Termios to a syscall.Termios.
 func tiosToSyscall(ut *unix.Termios) *syscall.Termios {
 	return &syscall.Termios{
-		Iflag:  ut.Iflag,
-		Oflag:  ut.Oflag,
-		Cflag:  ut.Cflag,
-		Lflag:  ut.Lflag,
-		Cc:     ut.Cc,
+		Iflag: ut.Iflag,
+		Oflag: ut.Oflag,
+		Cflag: ut.Cflag,
+		Lflag: ut.Lflag,
+		Cc:    ut.Cc,
 	}
 }


Test patch:
diff --git a/cli_test.go b/cli_test.go
index 0322707..8596d5b 100644
--- a/cli_test.go
+++ b/cli_test.go
@@ -41,6 +41,9 @@ var cliTests = map[string][]string{
 	// Test that help is printed if help flag is set, even if file is given
 	"DebugHelpFlag": {"test", "debug", "-h"},
 
+	"UnusedNoFilesHelp": {"test", "unused"},
+	"UnusedHelpFlag":    {"test", "unused", "-h"},
+
 	// Test that version is printed
 	"Version": {"test", "version"},
 }
diff --git a/tests/c4go-TestCLI-func1-UnusedHelpFlag b/tests/c4go-TestCLI-func1-UnusedHelpFlag
new file mode 100644
index 0000000..98a4a40
--- /dev/null
+++ b/tests/c4go-TestCLI-func1-UnusedHelpFlag
@@ -0,0 +1,2 @@
+(*bytes.Buffer)(  -h	print help information
+)
diff --git a/tests/c4go-TestCLI-func1-UnusedNoFilesHelp b/tests/c4go-TestCLI-func1-UnusedNoFilesHelp
new file mode 100644
index 0000000..98a4a40
--- /dev/null
+++ b/tests/c4go-TestCLI-func1-UnusedNoFilesHelp
@@ -0,0 +1,2 @@
+(*bytes.Buffer)(  -h	print help information
+)
diff --git a/types/dereference_test.go b/types/dereference_test.go
index 255507b..bcc8c2b 100644
--- a/types/dereference_test.go
+++ b/types/dereference_test.go
@@ -1,7 +1,9 @@
 package types
 
-import "testing"
-import "fmt"
+import (
+	"fmt"
+	"testing"
+)
 
 func TestGetDereferenceType(t *testing.T) {
 	type args struct {