From be3ff020ad71cec50614f6d4737fc91b21ada474 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 21 Sep 2022 10:25:41 +0700 Subject: [PATCH] go/analysis/passes/sortslice: correct diagnostic for sort.Slice(f()) Fixes golang/go#55098 Change-Id: I801279532c448bc4c9d5fce0cc3236e95fb77fdb Reviewed-on: https://go-review.googlesource.com/c/tools/+/431295 Reviewed-by: Johan Brandhorst-Satzkorn Auto-Submit: Cuong Manh Le Reviewed-by: Tim King Run-TryBot: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui gopls-CI: kokoro --- go/analysis/passes/sortslice/analyzer.go | 9 +++++++ .../passes/sortslice/testdata/src/a/a.go | 24 +++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/go/analysis/passes/sortslice/analyzer.go b/go/analysis/passes/sortslice/analyzer.go index 5eb957a188..f85837d66b 100644 --- a/go/analysis/passes/sortslice/analyzer.go +++ b/go/analysis/passes/sortslice/analyzer.go @@ -52,11 +52,20 @@ func run(pass *analysis.Pass) (interface{}, error) { arg := call.Args[0] typ := pass.TypesInfo.Types[arg].Type + + if tuple, ok := typ.(*types.Tuple); ok { + typ = tuple.At(0).Type() // special case for Slice(f(...)) + } + switch typ.Underlying().(type) { case *types.Slice, *types.Interface: return } + // Restore typ to the original type, we may unwrap the tuple above, + // typ might not be the type of arg. + typ = pass.TypesInfo.Types[arg].Type + var fixes []analysis.SuggestedFix switch v := typ.Underlying().(type) { case *types.Array: diff --git a/go/analysis/passes/sortslice/testdata/src/a/a.go b/go/analysis/passes/sortslice/testdata/src/a/a.go index bc6cc16e9f..c6aca8df13 100644 --- a/go/analysis/passes/sortslice/testdata/src/a/a.go +++ b/go/analysis/passes/sortslice/testdata/src/a/a.go @@ -6,8 +6,8 @@ import "sort" func IncorrectSort() { i := 5 sortFn := func(i, j int) bool { return false } - sort.Slice(i, sortFn) // want "sort.Slice's argument must be a slice; is called with int" - sort.SliceStable(i, sortFn) // want "sort.SliceStable's argument must be a slice; is called with int" + sort.Slice(i, sortFn) // want "sort.Slice's argument must be a slice; is called with int" + sort.SliceStable(i, sortFn) // want "sort.SliceStable's argument must be a slice; is called with int" sort.SliceIsSorted(i, sortFn) // want "sort.SliceIsSorted's argument must be a slice; is called with int" } @@ -62,3 +62,23 @@ func UnderlyingSlice() { sort.SliceStable(s, sortFn) sort.SliceIsSorted(s, sortFn) } + +// FunctionResultsAsArguments passes a function which returns two values +// that satisfy sort.Slice signature. It should not produce a diagnostic. +func FunctionResultsAsArguments() { + s := []string{"a", "z", "ooo"} + sort.Slice(less(s)) + sort.Slice(lessPtr(s)) // want `sort.Slice's argument must be a slice; is called with \(\*\[\]string,.*` +} + +func less(s []string) ([]string, func(i, j int) bool) { + return s, func(i, j int) bool { + return s[i] < s[j] + } +} + +func lessPtr(s []string) (*[]string, func(i, j int) bool) { + return &s, func(i, j int) bool { + return s[i] < s[j] + } +}