Repository: tikv/client-go
Pull request #1415 (2024-08-04 08:18:25)

*: Update golangci-lint to v1.59.1 and fix lint errors
The current version `v1.51.2` of `golangci-lint` report false positive errors (see https://github.com/tikv/client-go/actions/runs/10214979208/job/28310744852?pr=1414):

```
❯ golangci-lint run
../../opt/go1.21.0/src/slices/sort.go:67:7: undefined: min (typecheck)
                m = min(m, x[i])
                    ^
../../opt/go1.21.0/src/slices/sort.go:97:7: undefined: max (typecheck)
                m = max(m, x[i])
```

### Changes

- Update version of `golangci-lint` to `v1.59.1` in CI.
- Fix new lint errors:
  - Remove `depguard` linter as we do not deny any 3rd package. The `depguard` linter is by default in strict mode and deny and 3rd package. In another hand if change to `lax` mode the linter will complain that `depguard: must have an Allow and/or Deny package list`
  - Use new `unsafe.SliceXXX` methods to replace deprecated `reflect.SliceHeader`. 

The new lint errors:

```
❯ golangci-lint run
tikvrpc/endpoint.go:37:8: import 'github.com/pingcap/kvproto/pkg/metapb' is not allowed from list 'Main' (depguard)
import "github.com/pingcap/kvproto/pkg/metapb"
       ^
tikvrpc/tikvrpc.go:42:2: import 'github.com/pingcap/kvproto/pkg/coprocessor' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/coprocessor"
        ^
tikvrpc/tikvrpc.go:43:2: import 'github.com/pingcap/kvproto/pkg/debugpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/debugpb"
        ^
tikvrpc/tikvrpc.go:44:2: import 'github.com/pingcap/kvproto/pkg/errorpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/errorpb"
        ^
tikvrpc/tikvrpc.go:45:2: import 'github.com/pingcap/kvproto/pkg/kvrpcpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/kvrpcpb"
        ^
tikvrpc/tikvrpc.go:46:2: import 'github.com/pingcap/kvproto/pkg/metapb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/metapb"
        ^
tikvrpc/tikvrpc.go:47:2: import 'github.com/pingcap/kvproto/pkg/mpp' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/mpp"
        ^
tikvrpc/tikvrpc.go:48:2: import 'github.com/pingcap/kvproto/pkg/tikvpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/tikvpb"
        ^
tikvrpc/tikvrpc.go:49:2: import 'github.com/pkg/errors' is not allowed from list 'Main' (depguard)
        "github.com/pkg/errors"
        ^
tikvrpc/tikvrpc.go:50:2: import 'github.com/tikv/client-go/v2/kv' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/kv"
        ^
tikvrpc/tikvrpc.go:51:2: import 'github.com/tikv/client-go/v2/oracle' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/oracle"
        ^
tikvrpc/tikvrpc_test.go:44:2: import 'github.com/pingcap/kvproto/pkg/coprocessor' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/coprocessor"
        ^
tikvrpc/tikvrpc_test.go:45:2: import 'github.com/pingcap/kvproto/pkg/kvrpcpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/kvrpcpb"
        ^
tikvrpc/tikvrpc_test.go:46:2: import 'github.com/pingcap/kvproto/pkg/tikvpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/tikvpb"
        ^
tikvrpc/tikvrpc_test.go:47:2: import 'github.com/stretchr/testify/assert' is not allowed from list 'Main' (depguard)
        "github.com/stretchr/testify/assert"
        ^
oracle/oracles/local_test.go:42:2: import 'github.com/stretchr/testify/assert' is not allowed from list 'Main' (depguard)
        "github.com/stretchr/testify/assert"
        ^
oracle/oracles/local_test.go:43:2: import 'github.com/stretchr/testify/require' is not allowed from list 'Main' (depguard)
        "github.com/stretchr/testify/require"
        ^
oracle/oracles/local_test.go:44:2: import 'github.com/tikv/client-go/v2/oracle' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/oracle"
        ^
oracle/oracles/local_test.go:45:2: import 'github.com/tikv/client-go/v2/oracle/oracles' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/oracle/oracles"
        ^
oracle/oracles/pd_test.go:43:2: import 'github.com/stretchr/testify/assert' is not allowed from list 'Main' (depguard)
        "github.com/stretchr/testify/assert"
        ^
oracle/oracles/pd_test.go:44:2: import 'github.com/tikv/client-go/v2/oracle' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/oracle"
        ^
oracle/oracles/pd_test.go:45:2: import 'github.com/tikv/client-go/v2/oracle/oracles' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/oracle/oracles"
        ^
internal/apicodec/codec.go:6:2: import 'github.com/pingcap/errors' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/errors"
        ^
internal/apicodec/codec.go:7:2: import 'github.com/pingcap/kvproto/pkg/keyspacepb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/keyspacepb"
        ^
internal/apicodec/codec.go:8:2: import 'github.com/pingcap/kvproto/pkg/kvrpcpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/kvrpcpb"
        ^
internal/apicodec/codec.go:9:2: import 'github.com/tikv/client-go/v2/tikvrpc' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/tikvrpc"
        ^
internal/apicodec/codec_v1.go:4:2: import 'github.com/pingcap/errors' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/errors"
        ^
internal/apicodec/codec_v1.go:5:2: import 'github.com/pingcap/kvproto/pkg/errorpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/errorpb"
        ^
internal/apicodec/codec_v1.go:6:2: import 'github.com/pingcap/kvproto/pkg/keyspacepb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/keyspacepb"
        ^
internal/apicodec/codec_v1.go:8:2: import 'github.com/tikv/client-go/v2/tikvrpc' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/tikvrpc"
        ^
internal/apicodec/codec_v2.go:8:2: import 'github.com/pingcap/kvproto/pkg/coprocessor' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/coprocessor"
        ^
internal/apicodec/codec_v2.go:9:2: import 'github.com/pingcap/kvproto/pkg/errorpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/errorpb"
        ^
internal/apicodec/codec_v2.go:10:2: import 'github.com/pingcap/kvproto/pkg/keyspacepb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/keyspacepb"
        ^
internal/apicodec/codec_v2.go:12:2: import 'github.com/pingcap/kvproto/pkg/metapb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/metapb"
        ^
internal/apicodec/codec_v2.go:13:2: import 'github.com/pkg/errors' is not allowed from list 'Main' (depguard)
        "github.com/pkg/errors"
        ^
internal/apicodec/codec_v2.go:14:2: import 'github.com/tikv/client-go/v2/internal/logutil' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/internal/logutil"
        ^
internal/apicodec/codec_v2.go:15:2: import 'github.com/tikv/client-go/v2/tikvrpc' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/tikvrpc"
        ^
internal/apicodec/mem_codec.go:4:2: import 'github.com/pkg/errors' is not allowed from list 'Main' (depguard)
        "github.com/pkg/errors"
        ^
internal/apicodec/mem_codec.go:5:2: import 'github.com/tikv/client-go/v2/util/codec' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/util/codec"
        ^
internal/apicodec/codec_v2_test.go:12:2: import 'github.com/pingcap/kvproto/pkg/mpp' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/mpp"
        ^
internal/apicodec/codec_v2_test.go:13:2: import 'github.com/stretchr/testify/suite' is not allowed from list 'Main' (depguard)
        "github.com/stretchr/testify/suite"
        ^
internal/apicodec/codec_v2_test.go:15:2: import 'github.com/tikv/client-go/v2/util/codec' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/util/codec"
        ^
internal/client/client.go:50:2: import 'github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing' is not allowed from list 'Main' (depguard)
        grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
        ^
internal/client/client.go:51:2: import 'github.com/opentracing/opentracing-go' is not allowed from list 'Main' (depguard)
        "github.com/opentracing/opentracing-go"
        ^
internal/client/client.go:53:2: import 'github.com/pingcap/kvproto/pkg/debugpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/debugpb"
        ^
internal/client/client.go:54:2: import 'github.com/pingcap/kvproto/pkg/mpp' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/mpp"
        ^
internal/client/client.go:55:2: import 'github.com/pingcap/kvproto/pkg/tikvpb' is not allowed from list 'Main' (depguard)
        "github.com/pingcap/kvproto/pkg/tikvpb"
        ^
internal/client/client.go:57:2: import 'github.com/prometheus/client_golang/prometheus' is not allowed from list 'Main' (depguard)
        "github.com/prometheus/client_golang/prometheus"
        ^
internal/client/client.go:58:2: import 'github.com/tikv/client-go/v2/config' is not allowed from list 'Main' (depguard)
        "github.com/tikv/client-go/v2/config"
        ^
internal/client/client.go:59:2: import 'github.com/tikv/client-go/v2/error' is not allowed from list 'Main' (depguard)
        tikverr "github.com/tikv/client-go/v2/error"
        ^
util/misc.go:171:14: SA1019: reflect.SliceHeader has been deprecated since Go 1.21 and an alternative has been available since Go 1.17: Use unsafe.Slice or unsafe.SliceData instead. (staticcheck)
        pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
                    ^
util/misc.go:172:15: SA1019: reflect.StringHeader has been deprecated since Go 1.21 and an alternative has been available since Go 1.20: Use unsafe.String or unsafe.StringData instead. (staticcheck)
        pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
                     ^
internal/unionstore/memdb.go:841:11: SA1019: reflect.SliceHeader has been deprecated since Go 1.21 and an alternative has been available since Go 1.17: Use unsafe.Slice or unsafe.SliceData instead. (staticcheck)
        hdr := (*reflect.SliceHeader)(unsafe.Pointer(&ret))
                 ^
```



Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 2929ea4..997aabe 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -4,7 +4,6 @@ linters:
   disable-all: true
   enable:
     - bodyclose
-    - depguard
     - exportloopref
     - gofmt
     - goimports
diff --git a/internal/unionstore/memdb.go b/internal/unionstore/memdb.go
index 1aca2fa..3a6067b 100644
--- a/internal/unionstore/memdb.go
+++ b/internal/unionstore/memdb.go
@@ -38,7 +38,6 @@ import (
 	"bytes"
 	"fmt"
 	"math"
-	"reflect"
 	"sync"
 	"unsafe"
 
@@ -837,12 +836,8 @@ func (n *memdbNode) setBlack() {
 }
 
 func (n *memdbNode) getKey() []byte {
-	var ret []byte
-	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&ret))
-	hdr.Data = uintptr(unsafe.Pointer(&n.flags)) + kv.FlagBytes
-	hdr.Len = int(n.klen)
-	hdr.Cap = int(n.klen)
-	return ret
+	ptr := unsafe.Add(unsafe.Pointer(&n.flags), kv.FlagBytes)
+	return unsafe.Slice((*byte)(ptr), n.klen)
 }
 
 const (
diff --git a/util/misc.go b/util/misc.go
index e324bf7..9574a21 100644
--- a/util/misc.go
+++ b/util/misc.go
@@ -38,7 +38,6 @@ import (
 	"context"
 	"encoding/hex"
 	"fmt"
-	"reflect"
 	"strconv"
 	"strings"
 	"time"
@@ -164,15 +163,8 @@ func BytesToString(numBytes int64) string {
 }
 
 // String converts slice of bytes to string without copy.
-func String(b []byte) (s string) {
-	if len(b) == 0 {
-		return ""
-	}
-	pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
-	pstring.Data = pbytes.Data
-	pstring.Len = pbytes.Len
-	return
+func String(b []byte) string {
+	return unsafe.String(unsafe.SliceData(b), len(b))
 }
 
 // ToUpperASCIIInplace bytes.ToUpper but zero-cost


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 533a91a..a2cf5d1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -52,5 +52,5 @@ jobs:
       - name: Lint
         uses: golangci/golangci-lint-action@v3
         with:
-          version: v1.51.2
+          version: v1.59.1
 
diff --git a/util/misc_test.go b/util/misc_test.go
index ae819ac..71090f7 100644
--- a/util/misc_test.go
+++ b/util/misc_test.go
@@ -88,3 +88,12 @@ func TestCompatibleParseGCTime(t *testing.T) {
 		assert.NotNil(err)
 	}
 }
+
+func TestBytesToString(t *testing.T) {
+	assert := assert.New(t)
+
+	for _, str := range []string{"", "hello"} {
+		bytes := []byte(str)
+		assert.Equal(str, String(bytes))
+	}
+}