Skip to content

Instantly share code, notes, and snippets.

@YangKeao
Last active June 8, 2023 09:26
Show Gist options
  • Save YangKeao/94ecc2b4f40a338c5d1ef2b56991a8a4 to your computer and use it in GitHub Desktop.
Save YangKeao/94ecc2b4f40a338c5d1ef2b56991a8a4 to your computer and use it in GitHub Desktop.
Analyze all usage of `sessionctx.Context` in the "tidb/expression" package.
package main
import (
"fmt"
"go/ast"
"go/token"
"go/types"
"log"
"strings"
"golang.org/x/tools/go/packages"
)
var currentPkg = "expression"
type astVisitor struct {
pkg *packages.Package
file *ast.File
stack []ast.Node
allSels map[string][]token.Position
allCalls map[string][]token.Position
others []token.Position
}
func (v *astVisitor) Visit(n ast.Node) ast.Visitor {
var parent ast.Node
if v.stack != nil {
parent = v.stack[len(v.stack)-1]
}
isOthers := true
switch node := n.(type) {
case ast.Expr:
t := v.pkg.TypesInfo.TypeOf(node)
pos := v.pkg.Fset.Position(node.Pos())
if sessionctx, ok := t.(*types.Named); ok && strings.Contains(sessionctx.String(), "github.com/pingcap/tidb/sessionctx.Context") {
if sel, ok := parent.(*ast.SelectorExpr); ok {
// the parent of ctx is a selector expr, we can see which field/method it used
v.allSels["ctx."+sel.Sel.String()] = append(v.allSels["ctx."+sel.Sel.String()], pos)
isOthers = false
} else {
for i := len(v.stack) - 1; i >= 0; i-- {
p := v.stack[i]
switch pWithTyp := p.(type) {
case *ast.CallExpr:
typOfX := v.pkg.TypesInfo.TypeOf(pWithTyp.Fun)
if !strings.Contains(typOfX.String(), "tidb/"+currentPkg) && types.ExprString(pWithTyp.Fun) != currentPkg {
funCallStr := types.ExprString(pWithTyp.Fun)
v.allCalls[funCallStr] = append(v.allCalls[funCallStr], pos)
}
isOthers = false
break
case *ast.FuncType, *ast.StructType:
// ignore these cases
isOthers = false
break
}
}
}
if isOthers {
v.others = append(v.others, pos)
}
return nil
}
}
if n == nil {
// Done with node's children. Pop.
v.stack = v.stack[:len(v.stack)-1]
} else {
// Push the current node for children.
v.stack = append(v.stack, n)
}
return v
}
func main() {
packages, err := packages.Load(&packages.Config{
Mode: packages.NeedSyntax | packages.NeedTypes | packages.NeedImports | packages.NeedName | packages.NeedTypesInfo,
Dir: "/home/yangkeao/Project/github.com/YangKeao/tidb",
}, "/home/yangkeao/Project/github.com/YangKeao/tidb/"+currentPkg+"/...")
if err != nil {
log.Fatal(err)
}
allSels := make(map[string][]token.Position)
allCalls := make(map[string][]token.Position)
var others []token.Position
for _, pkg := range packages {
for _, file := range pkg.Syntax {
v := &astVisitor{
pkg: pkg,
file: file,
allSels: allSels,
allCalls: allCalls,
}
ast.Walk(v, file)
others = append(others, v.others...)
}
}
fmt.Println("Selectors:")
for sel, poses := range allSels {
for _, pos := range poses {
fmt.Printf("%s: %s\n", sel, pos.String())
}
}
fmt.Println("FunctionCalls:")
for call, poses := range allCalls {
for _, pos := range poses {
fmt.Printf("%s: %s\n", call, pos.String())
}
}
fmt.Println("Others:")
for _, pos := range others {
fmt.Printf("%s\n", pos.String())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment