func valSwap(m dsl.Matcher) {
	m.Match(`$tmp := $y; $y = $x; $x = $tmp`).
		Report("can re-write as `$y, $x = $x, $y`")
}
doc:summary Detects value swapping code that are not using parallel assignment
doc:tags    style
doc:before  *tmp = *x; *x = *y; *y = *tmp
doc:after   *x, *y = *y, *x
package gorules
import (
	"github.com/quasilyte/go-ruleguard/dsl"
)
func redundantSprint(m dsl.Matcher) {
	m.Match(`fmt.Sprint($x)`, `fmt.Sprintf("%s", $x)`, `fmt.Sprintf("%v", $x)`).
		Where(m["x"].Type.Implements(`fmt.Stringer`)).
		Suggest(`$x.String()`).
		Report(`use $x.String() instead`)
	m.Match(`fmt.Sprint($x)`, `fmt.Sprintf("%s", $x)`, `fmt.Sprintf("%v", $x)`).
		Where(m["x"].Type.Implements(`error`)).
		Suggest(`$x.Error()`).
		Report(`use $x.Error() instead`)
	m.Match(`fmt.Sprint($x)`, `fmt.Sprintf("%s", $x)`, `fmt.Sprintf("%v", $x)`).
		Where(m["x"].Type.Is(`string`)).
		Suggest(`$x`).
		Report(`$x is already string`)
}
func deferUnlambda(m dsl.Matcher) {
	m.Match(`defer func() { $f($*args) }()`).
		Where(m["f"].Node.Is(`Ident`) && m["f"].Text != "panic" && m["f"].Text != "recover" && m["args"].Const).
		Report("can rewrite as `defer $f($args)`")
	m.Match(`defer func() { $pkg.$f($*args) }()`).
		Where(m["f"].Node.Is(`Ident`) && m["args"].Const && m["pkg"].Object.Is(`PkgName`)).
		Report("can rewrite as `defer $pkg.$f($args)`")
}
func ioutilDeprecated(m dsl.Matcher) {
	m.Match(`ioutil.ReadAll($_)`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.ReadAll is deprecated, use io.ReadAll instead`)
	m.Match(`ioutil.ReadFile($_)`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.ReadFile is deprecated, use os.ReadFile instead`)
	m.Match(`ioutil.WriteFile($_, $_, $_)`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.WriteFile is deprecated, use os.WriteFile instead`)
	m.Match(`ioutil.ReadDir($_)`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.ReadDir is deprecated, use os.ReadDir instead`)
	m.Match(`ioutil.NopCloser($_)`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.NopCloser is deprecated, use io.NopCloser instead`)
	m.Match(`ioutil.Discard`).
		Where(m.GoVersion().GreaterEqThan("1.16")).
		Report(`ioutil.Discard is deprecated, use io.Discard instead`)
}
func badLock(m dsl.Matcher) {
	m.Match(`$mu1.Lock(); $mu2.Unlock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`defer is missing, mutex is unlocked immediately`).
		At(m["mu2"])
	m.Match(`$mu1.RLock(); $mu2.RUnlock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`defer is missing, mutex is unlocked immediately`).
		At(m["mu2"])
	m.Match(`$mu1.Lock(); defer $mu2.RUnlock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`suspicious unlock, maybe Unlock was intended?`).
		At(m["mu2"])
	m.Match(`$mu1.RLock(); defer $mu2.Unlock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`suspicious unlock, maybe RUnlock was intended?`).
		At(m["mu2"])
	m.Match(`$mu1.Lock(); defer $mu2.Lock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`maybe defer $mu1.Unlock() was intended?`).
		At(m["mu2"])
	m.Match(`$mu1.RLock(); defer $mu2.RLock()`).
		Where(m["mu1"].Text == m["mu2"].Text).
		Report(`maybe defer $mu1.RUnlock() was intended?`).
		At(m["mu2"])
}
func httpNoBody(m dsl.Matcher) {
	m.Match("http.NewRequest($method, $url, $nil)").
		Where(m["nil"].Text == "nil").
		Suggest("http.NewRequest($method, $url, http.NoBody)").
		Report("http.NoBody should be preferred to the nil request body")
	m.Match("http.NewRequestWithContext($ctx, $method, $url, $nil)").
		Where(m["nil"].Text == "nil").
		Suggest("http.NewRequestWithContext($ctx, $method, $url, http.NoBody)").
		Report("http.NoBody should be preferred to the nil request body")
}
func preferDecodeRune(m dsl.Matcher) {
	m.Match(`[]rune($s)[0]`).
		Where(m["s"].Type.Is(`string`)).
		Report(`consider replacing $$ with utf8.DecodeRuneInString($s)`)
}
func sloppyLen(m dsl.Matcher) {
	m.Match(`len($_) >= 0`).Report(`$$ is always true`)
	m.Match(`len($_) < 0`).Report(`$$ is always false`)
	m.Match(`len($x) <= 0`).Report(`$$ can be len($x) == 0`)
}