diff --git a/viruses/arithmetic/arithmetic.go b/viruses/arithmetic/arithmetic.go index a53c792..13aca86 100644 --- a/viruses/arithmetic/arithmetic.go +++ b/viruses/arithmetic/arithmetic.go @@ -33,6 +33,12 @@ func (v *Arithmetic) Incubate(node ast.Node, _ *types.Info) []*viruses.Infection return nil } + // Go overloaded the + operator, meaning is not just used for + // arithmetic operations, so it needs to be ignored for strings. + if isString(expression.X) || isString(expression.Y) { + return nil + } + originalOperation := expression.Op mutatedOperation, matches := v.mutations[expression.Op] @@ -48,3 +54,30 @@ func (v *Arithmetic) Incubate(node ast.Node, _ *types.Info) []*viruses.Infection ), } } + +func isString(expr ast.Expr) bool { + switch expr := expr.(type) { + case *ast.Ident: + // We need to get the type here, however, the `types` parameter + // is explicitly set to `nil` upon function invocation. + case *ast.BasicLit: + // Strings only support concatenation (+) + if expr.Kind == token.STRING { + return true + } + case *ast.CallExpr: + if expr, isIdentifier := expr.Fun.(*ast.Ident); isIdentifier { + // Make sure we have a builtin. + // Technically, we could encounter something like this: + // + // func string(b []byte) int { + // return len(b) + // } + if expr.Name == "string" && expr.Obj == nil { + return true + } + } + } + + return false +} diff --git a/viruses/arithmetic/arithmetic_test.go b/viruses/arithmetic/arithmetic_test.go index ae8ec84..ccdb009 100644 --- a/viruses/arithmetic/arithmetic_test.go +++ b/viruses/arithmetic/arithmetic_test.go @@ -12,7 +12,8 @@ func TestArithmetic(t *testing.T) { "Arithmetic", arithmetic.New(), oozetesting.Mutations{ - "no mutations": {"source.0.go", []string{}}, + "no mutations": {"source.0.go", []string{}}, + "no mutation of string concatenation": {"source.7.go", []string{}}, "one mutation + to -": {"source.1.go", []string{ "source.2.go", }}, diff --git a/viruses/arithmetic/testdata/source.7.go b/viruses/arithmetic/testdata/source.7.go new file mode 100644 index 0000000..fd2bbd6 --- /dev/null +++ b/viruses/arithmetic/testdata/source.7.go @@ -0,0 +1,37 @@ +//!go:build testdata + +package source + +func hello0() string { + x := "hello" + return "/" + x +} + +func hello1() string { + x := "hello" + return x + "/" +} + +func hello3() string { + x := "hello" + y := []byte("/") + return x + string(y) +} + +// FIXME This still fails +// func hello2() string { +// x := "hello" +// y := "/" +// return x + y +// } + +// FIXME This still fails +// func toString(b []byte) string { +// return string(x) +// } + +// func hello4() string { +// x := "hello" +// y := []byte{"/"} +// return hello + toString(y) +// }