github.com/prysmaticlabs/prysm@v1.4.4/tools/analyzers/comparesame/analyzer.go (about)

     1  // Package comparesame implements a static analyzer to ensure that code does not contain
     2  // comparisons of identical expressions.
     3  package comparesame
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"go/ast"
     9  	"go/printer"
    10  	"go/token"
    11  
    12  	"golang.org/x/tools/go/analysis"
    13  	"golang.org/x/tools/go/analysis/passes/inspect"
    14  	"golang.org/x/tools/go/ast/inspector"
    15  )
    16  
    17  // Doc explaining the tool.
    18  const Doc = "Tool to detect comparison (==, !=, >=, <=, >, <) of identical expressions."
    19  
    20  const messageTemplate = "Boolean expression has identical expressions on both sides. The result is always %v."
    21  
    22  // Analyzer runs static analysis.
    23  var Analyzer = &analysis.Analyzer{
    24  	Name:     "comparesame",
    25  	Doc:      Doc,
    26  	Requires: []*analysis.Analyzer{inspect.Analyzer},
    27  	Run:      run,
    28  }
    29  
    30  func run(pass *analysis.Pass) (interface{}, error) {
    31  	inspection, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    32  	if !ok {
    33  		return nil, errors.New("analyzer is not type *inspector.Inspector")
    34  	}
    35  
    36  	nodeFilter := []ast.Node{
    37  		(*ast.BinaryExpr)(nil),
    38  	}
    39  
    40  	inspection.Preorder(nodeFilter, func(node ast.Node) {
    41  		expr, ok := node.(*ast.BinaryExpr)
    42  		if !ok {
    43  			return
    44  		}
    45  
    46  		switch expr.Op {
    47  		case token.EQL, token.NEQ, token.GEQ, token.LEQ, token.GTR, token.LSS:
    48  			var xBuf, yBuf bytes.Buffer
    49  			if err := printer.Fprint(&xBuf, pass.Fset, expr.X); err != nil {
    50  				pass.Reportf(expr.X.Pos(), err.Error())
    51  			}
    52  			if err := printer.Fprint(&yBuf, pass.Fset, expr.Y); err != nil {
    53  				pass.Reportf(expr.Y.Pos(), err.Error())
    54  			}
    55  			if xBuf.String() == yBuf.String() {
    56  				switch expr.Op {
    57  				case token.EQL, token.NEQ, token.GEQ, token.LEQ:
    58  					pass.Reportf(expr.OpPos, messageTemplate, true)
    59  				case token.GTR, token.LSS:
    60  					pass.Reportf(expr.OpPos, messageTemplate, false)
    61  				}
    62  			}
    63  		}
    64  	})
    65  
    66  	return nil, nil
    67  }