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 }