Last active
June 8, 2023 09:26
-
-
Save YangKeao/94ecc2b4f40a338c5d1ef2b56991a8a4 to your computer and use it in GitHub Desktop.
Analyze all usage of `sessionctx.Context` in the "tidb/expression" package.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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