@@ -360,6 +360,51 @@ func TestDeclSelection_RemoveUnusedTypeConstraint(t *testing.T) {
360360 sel .InitCode .IsDead (`ghost = new Bar\[\d+ /\* int \*/\]\.ptr\(7\)` )
361361}
362362
363+ func TestLengthParenthesizingIssue841 (t * testing.T ) {
364+ // See issue https://github.com/gopherjs/gopherjs/issues/841
365+ //
366+ // Summary: Given `len(a+b)` where a and b are strings being concatenated
367+ // together, the result was `a + b.length` instead of `(a+b).length`.
368+ //
369+ // The fix was to check if the expression in `len` is a binary
370+ // expression or not. If it is, then the expression is parenthesized.
371+ // This will work for concatenations any combination of variables and
372+ // literals but won't pick up `len(Foo(a+b))` or `len(a[0:i+3])`.
373+
374+ src := `
375+ package main
376+
377+ func main() {
378+ a := "a"
379+ b := "b"
380+ ab := a + b
381+ if len(a+b) != len(ab) {
382+ panic("unreachable")
383+ }
384+ }`
385+
386+ srcFiles := []srctesting.Source {{Name : `main.go` , Contents : []byte (src )}}
387+ root := srctesting .ParseSources (t , srcFiles , nil )
388+ archives := compileProject (t , root , false )
389+ mainPkg := archives [root .PkgPath ]
390+
391+ badRegex := regexp .MustCompile (`a\s*\+\s*b\.length` )
392+ goodRegex := regexp .MustCompile (`\(a\s*\+\s*b\)\.length` )
393+ goodFound := false
394+ for i , decl := range mainPkg .Declarations {
395+ if badRegex .Match (decl .DeclCode ) {
396+ t .Errorf ("found length issue in decl #%d: %s" , i , decl .FullName )
397+ t .Logf ("decl code:\n %s" , string (decl .DeclCode ))
398+ }
399+ if goodRegex .Match (decl .DeclCode ) {
400+ goodFound = true
401+ }
402+ }
403+ if ! goodFound {
404+ t .Error ("parenthesized length not found" )
405+ }
406+ }
407+
363408func compareOrder (t * testing.T , sourceFiles []srctesting.Source , minify bool ) {
364409 t .Helper ()
365410 outputNormal := compile (t , sourceFiles , minify )
0 commit comments