Skip to content

Instantly share code, notes, and snippets.

@TACIXAT
Last active May 23, 2022 05:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TACIXAT/1000e7d873f0a8a738b3e720b4a7684c to your computer and use it in GitHub Desktop.
Save TACIXAT/1000e7d873f0a8a738b3e720b4a7684c to your computer and use it in GitHub Desktop.
Golang Application Specific Static Analysis - Checks if a funtion calls mismatched error functions
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
)
type CallChecker struct {
Name string
Calls []string
}
func (cc *CallChecker) CheckErrorFuncs() {
if len(cc.Calls) == 0 {
return
}
errorFuncs := map[string]int{}
for _, fn := range cc.Calls {
if fn == "jsonError" || fn == "errorPage" {
errorFuncs[fn] += 1
}
}
if len(errorFuncs) > 1 {
log.Println(
cc.Name, errorFuncs["jsonError"], errorFuncs["errorPage"])
}
}
func (cc *CallChecker) Report() {
if len(cc.Calls) == 0 {
return
}
log.Printf("%s:\n", cc.Name)
for _, fn := range cc.Calls {
log.Printf("\t%s\n", fn)
}
}
func (cc *CallChecker) Visit(node ast.Node) (w ast.Visitor) {
// if node != nil {
// log.Printf("%T: %s", node, node)
// }
switch node.(type) {
case *ast.CallExpr:
e := node.(*ast.CallExpr)
switch e.Fun.(type) {
case *ast.Ident:
id := e.Fun.(*ast.Ident)
cc.Calls = append(cc.Calls, id.String())
case *ast.SelectorExpr:
se := e.Fun.(*ast.SelectorExpr)
prefix := ""
switch se.X.(type) {
case *ast.Ident:
prefix = se.X.(*ast.Ident).String()
}
cc.Calls = append(
cc.Calls, fmt.Sprintf("%s.%s", prefix, se.Sel.String()))
}
}
return cc
}
func checkFunc(f *ast.FuncDecl) {
cc := &CallChecker{
Name: f.Name.String(),
Calls: []string{},
}
ast.Walk(cc, f)
// cc.Report()
cc.CheckErrorFuncs()
}
func main() {
var fname = flag.String("f", "", "file to parse")
flag.Parse()
if len(*fname) == 0 {
log.Fatal("-f required")
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, *fname, nil, 0)
if err != nil {
log.Println(err)
return
}
for _, d := range f.Decls {
switch d.(type) {
case *ast.FuncDecl:
f := d.(*ast.FuncDecl)
checkFunc(f)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment