github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/optimize-operands-order.go (about) 1 package rule 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/token" 7 8 "github.com/songshiyun/revive/lint" 9 ) 10 11 // OptimizeOperandsOrderRule lints given else constructs. 12 type OptimizeOperandsOrderRule struct{} 13 14 // Apply applies the rule to given file. 15 func (r *OptimizeOperandsOrderRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 16 var failures []lint.Failure 17 18 onFailure := func(failure lint.Failure) { 19 failures = append(failures, failure) 20 } 21 w := lintOptimizeOperandsOrderlExpr{ 22 onFailure: onFailure, 23 } 24 ast.Walk(w, file.AST) 25 return failures 26 } 27 28 // Name returns the rule name. 29 func (r *OptimizeOperandsOrderRule) Name() string { 30 return "optimize-operands-order" 31 } 32 33 type lintOptimizeOperandsOrderlExpr struct { 34 onFailure func(failure lint.Failure) 35 } 36 37 // Visit checks boolean AND and OR expressions to determine 38 // if swapping their operands may result in an execution speedup. 39 func (w lintOptimizeOperandsOrderlExpr) Visit(node ast.Node) ast.Visitor { 40 binExpr, ok := node.(*ast.BinaryExpr) 41 if !ok { 42 return w 43 } 44 45 switch binExpr.Op { 46 case token.LAND, token.LOR: 47 default: 48 return w 49 } 50 51 isCaller := func(n ast.Node) bool { 52 _, ok := n.(*ast.CallExpr) 53 return ok 54 } 55 56 // check if the left sub-expression contains a function call 57 nodes := pick(binExpr.X, isCaller, nil) 58 if len(nodes) < 1 { 59 return w 60 } 61 62 // check if the right sub-expression does not contain a function call 63 nodes = pick(binExpr.Y, isCaller, nil) 64 if len(nodes) > 0 { 65 return w 66 } 67 68 newExpr := ast.BinaryExpr{X: binExpr.Y, Y: binExpr.X, Op: binExpr.Op} 69 w.onFailure(lint.Failure{ 70 Failure: fmt.Sprintf("for better performance '%v' might be rewritten as '%v'", gofmt(binExpr), gofmt(&newExpr)), 71 Node: node, 72 Category: "optimization", 73 Confidence: 0.3, 74 }) 75 76 return w 77 }