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  }