github.com/ledgerwatch/erigon-lib@v1.0.0/rules.go (about)

     1  //go:build gorules
     2  // +build gorules
     3  
     4  package gorules
     5  
     6  // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
     7  // to apply changes in this file, please do: ./build/bin/golangci-lint cache clean
     8  import (
     9  	"github.com/quasilyte/go-ruleguard/dsl"
    10  	//quasilyterules "github.com/quasilyte/ruleguard-rules-test"
    11  )
    12  
    13  func init() {
    14  	//dsl.ImportRules("qrules", quasilyterules.Bundle)
    15  }
    16  
    17  func txDeferRollback(m dsl.Matcher) {
    18  	// Common pattern for long-living transactions:
    19  	//	tx, err := db.Begin()
    20  	//	if err != nil {
    21  	//		return err
    22  	//	}
    23  	//	defer tx.Rollback()
    24  	//
    25  	//	... code which uses database in transaction
    26  	//
    27  	//	err := tx.Commit()
    28  	//	if err != nil {
    29  	//		return err
    30  	//	}
    31  
    32  	m.Match(
    33  		`$tx, $err := $db.BeginRw($ctx); $chk; $rollback`,
    34  		`$tx, $err = $db.BeginRw($ctx); $chk; $rollback`,
    35  		`$tx, $err := $db.Begin($ctx); $chk; $rollback`,
    36  		`$tx, $err = $db.Begin($ctx); $chk; $rollback`,
    37  	).
    38  		Where(!m["rollback"].Text.Matches(`defer .*\.Rollback()`)).
    39  		//At(m["rollback"]).
    40  		Report(`Add "defer $tx.Rollback()" right after transaction creation error check. 
    41  			If you are in the loop - consider use "$db.View" or "$db.Update" or extract whole transaction to function.
    42  			Without rollback in defer - app can deadlock on error or panic.
    43  			Rules are in ./rules.go file.
    44  			`)
    45  }
    46  
    47  func closeCollector(m dsl.Matcher) {
    48  	m.Match(`$c := etl.NewCollector($*_); $close`).
    49  		Where(!m["close"].Text.Matches(`defer .*\.Close()`)).
    50  		Report(`Add "defer $c.Close()" right after collector creation`)
    51  }
    52  
    53  func closeLockedDir(m dsl.Matcher) {
    54  	m.Match(`$c := dir.OpenRw($*_); $close`).
    55  		Where(!m["close"].Text.Matches(`defer .*\.Close()`)).
    56  		Report(`Add "defer $c.Close()" after locked.OpenDir`)
    57  }
    58  
    59  func passValuesByContext(m dsl.Matcher) {
    60  	m.Match(`ctx.WithValue($*_)`).Report(`Don't pass app-level parameters by context, pass them as-is or as typed objects`)
    61  }
    62  
    63  func mismatchingUnlock(m dsl.Matcher) {
    64  	// By default, an entire match position is used as a location.
    65  	// This can be changed by the At() method that binds the location
    66  	// to the provided named submatch.
    67  	//
    68  	// In the rules below text editor would get mismatching method
    69  	// name locations:
    70  	//
    71  	//   defer mu.RUnlock()
    72  	//            ^^^^^^^
    73  
    74  	m.Match(`$mu.Lock(); defer $mu.$unlock()`).
    75  		Where(m["unlock"].Text == "RUnlock").
    76  		At(m["unlock"]).
    77  		Report(`maybe $2mu.Unlock() was intended?
    78  			Rules are in ./rules.go file.`)
    79  
    80  	m.Match(`$mu.RLock(); defer $mu.$unlock()`).
    81  		Where(m["unlock"].Text == "Unlock").
    82  		At(m["unlock"]).
    83  		Report(`maybe $mu.RUnlock() was intended?
    84  			Rules are in ./rules.go file.`)
    85  }