github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/constant-logical-expr.go (about)

     1  package rule
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  
     7  	"github.com/songshiyun/revive/lint"
     8  )
     9  
    10  // ConstantLogicalExprRule warns on constant logical expressions.
    11  type ConstantLogicalExprRule struct{}
    12  
    13  // Apply applies the rule to given file.
    14  func (r *ConstantLogicalExprRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    15  	var failures []lint.Failure
    16  
    17  	onFailure := func(failure lint.Failure) {
    18  		failures = append(failures, failure)
    19  	}
    20  
    21  	astFile := file.AST
    22  	w := &lintConstantLogicalExpr{astFile, onFailure}
    23  	ast.Walk(w, astFile)
    24  	return failures
    25  }
    26  
    27  // Name returns the rule name.
    28  func (r *ConstantLogicalExprRule) Name() string {
    29  	return "constant-logical-expr"
    30  }
    31  
    32  type lintConstantLogicalExpr struct {
    33  	file      *ast.File
    34  	onFailure func(lint.Failure)
    35  }
    36  
    37  func (w *lintConstantLogicalExpr) Visit(node ast.Node) ast.Visitor {
    38  	switch n := node.(type) {
    39  	case *ast.BinaryExpr:
    40  		if !w.isOperatorWithLogicalResult(n.Op) {
    41  			return w
    42  		}
    43  
    44  		if gofmt(n.X) != gofmt(n.Y) { // check if subexpressions are the same
    45  			return w
    46  		}
    47  
    48  		// Handles cases like: a <= a, a == a, a >= a
    49  		if w.isEqualityOperator(n.Op) {
    50  			w.newFailure(n, "expression always evaluates to true")
    51  			return w
    52  		}
    53  
    54  		// Handles cases like: a < a, a > a, a != a
    55  		if w.isInequalityOperator(n.Op) {
    56  			w.newFailure(n, "expression always evaluates to false")
    57  			return w
    58  		}
    59  
    60  		w.newFailure(n, "left and right hand-side sub-expressions are the same")
    61  	}
    62  
    63  	return w
    64  }
    65  
    66  func (w *lintConstantLogicalExpr) isOperatorWithLogicalResult(t token.Token) bool {
    67  	switch t {
    68  	case token.LAND, token.LOR, token.EQL, token.LSS, token.GTR, token.NEQ, token.LEQ, token.GEQ:
    69  		return true
    70  	}
    71  
    72  	return false
    73  }
    74  
    75  func (w *lintConstantLogicalExpr) isEqualityOperator(t token.Token) bool {
    76  	switch t {
    77  	case token.EQL, token.LEQ, token.GEQ:
    78  		return true
    79  	}
    80  
    81  	return false
    82  }
    83  
    84  func (w *lintConstantLogicalExpr) isInequalityOperator(t token.Token) bool {
    85  	switch t {
    86  	case token.LSS, token.GTR, token.NEQ:
    87  		return true
    88  	}
    89  
    90  	return false
    91  }
    92  
    93  func (w lintConstantLogicalExpr) newFailure(node ast.Node, msg string) {
    94  	w.onFailure(lint.Failure{
    95  		Confidence: 1,
    96  		Node:       node,
    97  		Category:   "logic",
    98  		Failure:    msg,
    99  	})
   100  }