github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/unused.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/parser"
     7  	"go/token"
     8  	"os"
     9  	"sort"
    10  )
    11  
    12  func unused(filenames ...string) {
    13  	for _, src := range filenames {
    14  		fset := token.NewFileSet() // positions are relative to fset
    15  
    16  		// Parse src but stop after processing the imports.
    17  		f, err := parser.ParseFile(fset, src, nil, parser.ParseComments)
    18  		if err != nil {
    19  			fmt.Fprintf(os.Stderr, "%v", err)
    20  			return
    21  		}
    22  
    23  		// map
    24  		m := map[string][]string{}
    25  
    26  		// Print the imports from the file's AST.
    27  		for i := range f.Decls {
    28  			decls := f.Decls[i]
    29  			if fd, ok := decls.(*ast.FuncDecl); ok {
    30  				name := fd.Name.Name
    31  				var cs CallSearcher
    32  				ast.Walk(&cs, fd)
    33  				m[name] = cs.used
    34  			}
    35  		}
    36  
    37  		// list of all function
    38  		used := map[string]bool{}
    39  		list := []string{"main"}
    40  
    41  		for iter := len(m) * 10; iter > 0; iter-- {
    42  		rem:
    43  			sort.Strings(list)
    44  			for i := range list {
    45  				if i == 0 {
    46  					continue
    47  				}
    48  				if list[i-1] == list[i] {
    49  					// remove from list
    50  					list = append(list[:i], list[i+1:]...)
    51  					goto rem
    52  				}
    53  			}
    54  			for i := range list {
    55  				_, ok := used[list[i]]
    56  				if ok {
    57  					// remove from list
    58  					list = append(list[:i], list[i+1:]...)
    59  					goto rem
    60  				}
    61  			}
    62  			var newlist []string
    63  			for k, v := range m {
    64  				for i := range list {
    65  					used[list[i]] = true
    66  					if k == list[i] {
    67  						used[k] = true
    68  						newlist = append(newlist, v...)
    69  					}
    70  				}
    71  			}
    72  			list = newlist
    73  		}
    74  
    75  		// full list
    76  		full := map[string]bool{}
    77  		for k, v := range m {
    78  			full[k] = true
    79  			for i := range v {
    80  				full[v[i]] = true
    81  			}
    82  		}
    83  
    84  		// unused
    85  		for k := range full {
    86  			_, ok := used[k]
    87  			if ok {
    88  				continue
    89  			}
    90  			fmt.Fprintf(os.Stdout, "%s\n", k)
    91  		}
    92  	}
    93  }
    94  
    95  type CallSearcher struct {
    96  	used []string
    97  }
    98  
    99  var GoFuncs = []string{
   100  	"len", "make", "append",
   101  	"string",
   102  	"float64", "float32",
   103  	"int", "int64", "int32", "int16",
   104  	"go", "close",
   105  	"panic",
   106  }
   107  
   108  func (c *CallSearcher) Visit(node ast.Node) (w ast.Visitor) {
   109  	if call, ok := node.(*ast.CallExpr); ok {
   110  		if f, ok := call.Fun.(*ast.Ident); ok {
   111  			isFound := false
   112  			for i := range GoFuncs {
   113  				if f.Name == GoFuncs[i] {
   114  					isFound = true
   115  				}
   116  			}
   117  			if !isFound {
   118  				c.used = append(c.used, f.Name)
   119  			}
   120  		}
   121  	}
   122  	return c
   123  }
   124  
   125  func search(f *ast.FuncDecl) (used []string) {
   126  
   127  	return
   128  }