Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip pre-allocated slices #26

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 44 additions & 7 deletions pkg/prealloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
if !ok {
continue
}
var isArrType bool
switch val := vSpec.Type.(type) {
case *ast.ArrayType:
isArrType = true
case *ast.Ident:
isArrType = contains(v.arrayTypes, val.Name)

var isArrType = v.isArrayType(vSpec.Type)
if len(vSpec.Values) > 0 {
callExpr, ok := vSpec.Values[0].(*ast.CallExpr)
if ok && isMakeFunc(callExpr) && len(callExpr.Args) > 0 {
isArrType = v.isArrayType(callExpr.Args[0])
}
}

if isArrType {
if vSpec.Names != nil {
/*atID, ok := arrayType.Elt.(*ast.Ident)
Expand All @@ -109,7 +111,11 @@ func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
}*/

// We should handle multiple slices declared on same line e.g. var mySlice1, mySlice2 []uint32
for _, vName := range vSpec.Names {
for index, vName := range vSpec.Names {
// Skip pre-allocated slices
if index < len(vSpec.Values) && preAllocated(vSpec.Values[index]) {
continue
}
v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: vName.Name /*sType: atID.Name,*/, genD: genD})
}
}
Expand Down Expand Up @@ -248,6 +254,17 @@ func (v *returnsVisitor) handleLoops(blockStmt *ast.BlockStmt) {

}

// handleLoops is a helper function to check whether a expr is array type
func (v *returnsVisitor) isArrayType(expr ast.Expr) bool {
switch val := expr.(type) {
case *ast.ArrayType:
return true
case *ast.Ident:
return contains(v.arrayTypes, val.Name)
}
return false
}

// Hint stores the information about an occurrence of a slice that could be
// preallocated.
type Hint struct {
Expand All @@ -265,3 +282,23 @@ func (h Hint) StringFromFS(f *token.FileSet) string {

return fmt.Sprintf("%v:%v Consider preallocating %v", file.Name(), lineNumber, h.DeclaredSliceName)
}

func preAllocated(expr ast.Expr) bool {
callExpr, ok := expr.(*ast.CallExpr)
if !ok || !isMakeFunc(callExpr) {
return false
}
if len(callExpr.Args) > 2 {
literal, ok := callExpr.Args[len(callExpr.Args)-1].(*ast.BasicLit)
return ok && literal.Value != "0"
}
return false
}

func isMakeFunc(callExpr *ast.CallExpr) bool {
funcIdent, ok := callExpr.Fun.(*ast.Ident)
if !ok {
return false
}
return funcIdent.Name == "make"
}
7 changes: 7 additions & 0 deletions testdata/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ func main() {
var z, w, v, u, s []int
var t [][]int
var intChan chan int
var p, q = make([]int, 0, 10), make([]int, 0)

for i, r := range "Hello" {
// x is already pre-allocated
Expand All @@ -26,6 +27,12 @@ func main() {

// t is a candidate for pre-allocation
t = append(t, foo(i))

// p is not a candidate for pre-allocation since it has been pre-allocated
p = append(p, i)

// q is a candidate for pre-allocation
q = append(q, i)
}

for i := range intChan {
Expand Down