compiler: disallow unnamed parameters for exported methods
This commit is contained in:
parent
d84f8940f1
commit
94f6a9ee61
3 changed files with 96 additions and 0 deletions
|
@ -2,6 +2,7 @@ package compiler
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
@ -12,6 +13,9 @@ import (
|
|||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
// ErrMissingExportedParamName is returned when exported contract method has unnamed parameter.
|
||||
var ErrMissingExportedParamName = errors.New("exported method is not allowed to have unnamed parameter")
|
||||
|
||||
var (
|
||||
// Go language builtin functions.
|
||||
goBuiltins = []string{"len", "append", "panic", "make", "copy", "recover", "delete"}
|
||||
|
@ -284,12 +288,31 @@ func (c *codegen) analyzeFuncUsage() funcUsage {
|
|||
if isMain && n.Name.IsExported() || isInitFunc(n) || isDeployFunc(n) {
|
||||
diff[name] = true
|
||||
}
|
||||
if isMain && n.Name.IsExported() {
|
||||
if n.Type.Params.List != nil {
|
||||
for i, param := range n.Type.Params.List {
|
||||
if param.Names == nil {
|
||||
c.prog.Err = fmt.Errorf("%w: %s", ErrMissingExportedParamName, n.Name)
|
||||
return false // Program is invalid.
|
||||
}
|
||||
for _, name := range param.Names {
|
||||
if name == nil || name.Name == "_" {
|
||||
c.prog.Err = fmt.Errorf("%w: %s/%d", ErrMissingExportedParamName, n.Name, i)
|
||||
return false // Program is invalid.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeCache[name] = declPair{n, c.importMap, pkgPath}
|
||||
return false // will be processed in the next stage
|
||||
}
|
||||
return true
|
||||
})
|
||||
})
|
||||
if c.prog.Err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
usage := funcUsage{}
|
||||
for len(diff) != 0 {
|
||||
|
|
|
@ -2106,6 +2106,9 @@ func (c *codegen) compile(info *buildInfo, pkg *packages.Package) error {
|
|||
c.analyzePkgOrder()
|
||||
c.fillDocumentInfo()
|
||||
funUsage := c.analyzeFuncUsage()
|
||||
if c.prog.Err != nil {
|
||||
return c.prog.Err
|
||||
}
|
||||
|
||||
// Bring all imported functions into scope.
|
||||
c.ForEachFile(c.resolveFuncDecls)
|
||||
|
|
|
@ -343,3 +343,73 @@ func TestInvokedContractsPermissons(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnnamedParameterCheck(t *testing.T) {
|
||||
t.Run("single argument", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func Main(_ int) int {
|
||||
x := 10
|
||||
return x
|
||||
}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, compiler.ErrMissingExportedParamName)
|
||||
})
|
||||
t.Run("several arguments", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func Main(a int, b string, _ int) int {
|
||||
x := 10
|
||||
return x
|
||||
}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, compiler.ErrMissingExportedParamName)
|
||||
})
|
||||
t.Run("interface", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func OnNEP17Payment(h string, i int, _ interface{}){}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, compiler.ErrMissingExportedParamName)
|
||||
})
|
||||
t.Run("a set of unnamed params", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func OnNEP17Payment(_ string, _ int, _ interface{}){}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, compiler.ErrMissingExportedParamName)
|
||||
})
|
||||
t.Run("mixed named and unnamed params", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func OnNEP17Payment(s0, _, s2 string){}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, compiler.ErrMissingExportedParamName)
|
||||
})
|
||||
t.Run("empty args", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func OnNEP17Payment(){}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
src := `
|
||||
package testcase
|
||||
func OnNEP17Payment(s string, i int, iface interface{}){}
|
||||
`
|
||||
_, _, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue