Ruleguard by example: Underlying types

package gorules

import ""

// The binary.Write function from the "encoding/binary" package
// does a simple Write call if the data argument is []byte.
// In that case we may want to suggest calling the Write method
// directly, without extra binary.Write overhead.
// But what if the data is not exactly []byte, but some named
// type that is defined like this: `type myBytes []byte`.
// It's still bytes, right?

func binaryWrite(m dsl.Matcher) {
	// When we consider myBytes type we need to remember that
	// it's *underlying* type is []byte. The underlying type
	// of []byte is []byte.
	// This leads us to the Underlying() method of the ExprType.

	m.Match(`binary.Write($w, $_, $v)`).
		Report(`consider doing $w.Write($v) instead`)
$ ruleguard -c 0 -rules rules.go main.go
main.go:19:2: consider doing buf.Write(b) instead
19		binary.Write(buf, binary.LittleEndian, b)
main.go:22:2: consider doing buf.Write(customBytes) instead
22		binary.Write(buf, binary.LittleEndian, customBytes)
main.go:23:2: consider doing buf.Write(myByteSlice2("123")) instead
23		binary.Write(buf, binary.LittleEndian, myByteSlice2("123"))
package main

import (

// myByteSlice underlying type is []byte
type myByteSlice []byte

// myByteSlice2 underlying type is still []byte.
type myByteSlice2 myByteSlice

func main() {
	var b []byte
	var customBytes myByteSlice
	buf := &bytes.Buffer{}

	binary.Write(buf, binary.LittleEndian, b)

	// These 2 lines will not give any warnings if we don't use Underlying().
	binary.Write(buf, binary.LittleEndian, customBytes)
	binary.Write(buf, binary.LittleEndian, myByteSlice2("123"))

	binary.Write(buf, binary.LittleEndian, 14) // OK: not []byte


To index Next: Node predicates Edit this page