Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e890dcd

Browse files
Merge pull request #1391 from Workiva/reservedWorkLabels
Fixing a problem with reserved words being used in labels
2 parents f3e2f1d + 7c2694c commit e890dcd

File tree

8 files changed

+179
-17
lines changed

8 files changed

+179
-17
lines changed

compiler/compiler.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ func init() {
4343
}
4444
}
4545

46+
// sanitizeName returns the given name unless it is a reserved JavaScript keyword
47+
// then it will append a '$' suffix to it to keep it from causing syntax errors in JS.
48+
func sanitizeName(name string) string {
49+
if reservedKeywords[name] {
50+
name += "$"
51+
}
52+
return name
53+
}
54+
4655
// Archive contains intermediate build outputs of a single package.
4756
//
4857
// This is a logical equivalent of an object file in traditional compilers.

compiler/decls.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,10 +599,7 @@ func (fc *funcContext) structConstructor(t *types.Struct) string {
599599
// function for runtime reflection. It returns isPtr=true if the method belongs
600600
// to the pointer-receiver method list.
601601
func (fc *funcContext) methodListEntry(method *types.Func) (entry string, isPtr bool) {
602-
name := method.Name()
603-
if reservedKeywords[name] {
604-
name += "$"
605-
}
602+
name := sanitizeName(method.Name())
606603
pkgPath := ""
607604
if !method.Exported() {
608605
pkgPath = method.Pkg().Path()

compiler/statements.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
109109

110110
if label != nil || analysis.HasBreak(clause) {
111111
if label != nil {
112-
fc.Printf("%s:", label.Name())
112+
fc.Printf("%s:", sanitizeName(label.Name()))
113113
}
114114
fc.Printf("switch (0) { default:")
115115
fc.Indented(func() {
@@ -306,7 +306,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
306306
blockingLabel := ""
307307
data := fc.flowDatas[nil]
308308
if s.Label != nil {
309-
normalLabel = " " + s.Label.Name
309+
normalLabel = " " + sanitizeName(s.Label.Name)
310310
blockingLabel = " s" // use explicit label "s", because surrounding loop may not be flattened
311311
data = fc.flowDatas[fc.pkgCtx.Uses[s.Label].(*types.Label)]
312312
}
@@ -317,7 +317,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
317317
data.postStmt()
318318
fc.PrintCond(data.beginCase == 0, fmt.Sprintf("continue%s;", normalLabel), fmt.Sprintf("$s = %d; continue%s;", data.beginCase, blockingLabel))
319319
case token.GOTO:
320-
fc.PrintCond(false, "goto "+s.Label.Name, fmt.Sprintf("$s = %d; continue;", fc.labelCase(fc.pkgCtx.Uses[s.Label].(*types.Label))))
320+
fc.PrintCond(false, "goto"+normalLabel, fmt.Sprintf("$s = %d; continue;", fc.labelCase(fc.pkgCtx.Uses[s.Label].(*types.Label))))
321321
case token.FALLTHROUGH:
322322
// handled in CaseClause
323323
default:
@@ -461,7 +461,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
461461
case *ast.LabeledStmt:
462462
label := fc.pkgCtx.Defs[s.Label].(*types.Label)
463463
if fc.GotoLabel[label] {
464-
fc.PrintCond(false, s.Label.Name+":", fmt.Sprintf("case %d:", fc.labelCase(label)))
464+
fc.PrintCond(false, sanitizeName(s.Label.Name)+":", fmt.Sprintf("case %d:", fc.labelCase(label)))
465465
}
466466
fc.translateStmt(s.Stmt, label)
467467

@@ -586,7 +586,7 @@ func (fc *funcContext) translateBranchingStmt(caseClauses []*ast.CaseClause, def
586586
}
587587

588588
if label != nil && !flatten {
589-
fc.Printf("%s:", label.Name())
589+
fc.Printf("%s:", sanitizeName(label.Name()))
590590
}
591591

592592
condStrs := make([]string, len(caseClauses))
@@ -652,7 +652,7 @@ func (fc *funcContext) translateLoopingStmt(cond func() string, body *ast.BlockS
652652
}()
653653

654654
if !flatten && label != nil {
655-
fc.Printf("%s:", label.Name())
655+
fc.Printf("%s:", sanitizeName(label.Name()))
656656
}
657657
isTerminated := false
658658
fc.PrintCond(!flatten, "while (true) {", fmt.Sprintf("case %d:", data.beginCase))

compiler/utils.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (fc *funcContext) Printf(format string, values ...any) {
5757

5858
func (fc *funcContext) PrintCond(cond bool, onTrue, onFalse string) {
5959
if !cond {
60-
fc.Printf("/* %s */ %s", strings.Replace(onTrue, "*/", "<star>/", -1), onFalse)
60+
fc.Printf("/* %s */ %s", strings.ReplaceAll(onTrue, "*/", "<star>/"), onFalse)
6161
return
6262
}
6363
fc.Printf("%s", onTrue)
@@ -477,13 +477,9 @@ func (fc *funcContext) methodName(fun *types.Func) string {
477477
if fun.Type().(*types.Signature).Recv() == nil {
478478
panic(fmt.Errorf("expected a method, got a standalone function %v", fun))
479479
}
480-
name := fun.Name()
481480
// Method names are scoped to their receiver type and guaranteed to be
482481
// unique within that, so we only need to make sure it's not a reserved keyword
483-
if reservedKeywords[name] {
484-
name += "$"
485-
}
486-
return name
482+
return sanitizeName(fun.Name())
487483
}
488484

489485
func (fc *funcContext) varPtrName(o *types.Var) string {

tests/gencircle_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ func Test_GenCircle_Trammel(t *testing.T) { runGenCircleTest(t, `trammel`) }
2929
var _ embed.FS
3030

3131
func runGenCircleTest(t *testing.T, testPkg string) {
32+
t.Helper()
33+
const basePath = `testdata/gencircle`
34+
runOutputTest(t, basePath, testPkg)
35+
}
36+
37+
func runOutputTest(t *testing.T, basePath, testPkg string) {
3238
t.Helper()
3339
if runtime.GOOS == `js` {
3440
t.Skip(`test meant to be run using normal Go compiler (needs os/exec)`)
3541
}
3642

3743
const (
38-
basePath = `testdata/gencircle`
3944
mainFile = `main.go`
4045
outFile = `main.out`
4146
)

tests/integration_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tests_test
2+
3+
import "testing"
4+
5+
// Test_JSReservedWords uses testdata/reserved/main.go
6+
// to test that JS reserved words can be used as labels, variable names, etc.
7+
func Test_JSReservedWords(t *testing.T) { runOutputTest(t, `testdata`, `reserved`) }

tests/testdata/reserved/main.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
reservedLoopLabel()
7+
reservedGotoLabel()
8+
reservedSwitchCaseLabel()
9+
reservedSwitchLabelInCase()
10+
reservedLabelledSwitch()
11+
reservedLabelledBranch()
12+
reservedSelectLabel()
13+
reservedTypeSwitchLabel()
14+
}
15+
16+
func reservedLoopLabel() {
17+
values := []int{}
18+
class:
19+
for i := 0; i < 10; i++ {
20+
if i%2 == 0 {
21+
continue class
22+
}
23+
if i > 7 {
24+
break class
25+
}
26+
values = append(values, i)
27+
}
28+
fmt.Println(`reservedLoopLabel:`, values)
29+
}
30+
31+
func reservedGotoLabel() {
32+
values := []int{}
33+
i := 0
34+
class:
35+
if i < 5 {
36+
i++
37+
values = append(values, i)
38+
goto class
39+
}
40+
fmt.Println(`reservedGotoLabel:`, values)
41+
}
42+
43+
func reservedSwitchCaseLabel() {
44+
values := []int{}
45+
const class = 2
46+
for i := 0; i < 3; i++ {
47+
switch i {
48+
case class:
49+
values = append(values, 42)
50+
default:
51+
values = append(values, i)
52+
}
53+
}
54+
fmt.Println(`reservedSwitchCaseLabel:`, values)
55+
}
56+
57+
func reservedSwitchLabelInCase() {
58+
values := []int{}
59+
for i := 0; i < 5; i++ {
60+
switch {
61+
case i < 3:
62+
if i == 2 {
63+
goto class
64+
}
65+
values = append(values, 99)
66+
break
67+
class:
68+
values = append(values, 42)
69+
default:
70+
values = append(values, i)
71+
}
72+
}
73+
fmt.Println(`reservedSwitchLabelInCase:`, values)
74+
}
75+
76+
func reservedLabelledSwitch() {
77+
values := []int{}
78+
for i := 0; i < 5; i++ {
79+
class:
80+
switch {
81+
case i < 3:
82+
i++
83+
break class
84+
default:
85+
values = append(values, i)
86+
}
87+
}
88+
fmt.Println(`reservedLabelledSwitch:`, values)
89+
}
90+
91+
func reservedLabelledBranch() {
92+
values := []int{}
93+
i := 0
94+
class:
95+
if i < 3 {
96+
i++
97+
goto class
98+
} else {
99+
values = append(values, i)
100+
}
101+
fmt.Println(`reservedLabelledBranch:`, values)
102+
}
103+
104+
func reservedSelectLabel() {
105+
class := make(chan int, 2)
106+
class <- 42
107+
values := []int{}
108+
for i := 0; i < 3; i++ {
109+
select {
110+
case v := <-class:
111+
values = append(values, v)
112+
default:
113+
values = append(values, i)
114+
}
115+
}
116+
fmt.Println(`reservedSelectLabel:`, values)
117+
}
118+
119+
type class interface {
120+
class_() int
121+
}
122+
123+
type classImpl struct{}
124+
125+
func (c *classImpl) class_() int { return 42 }
126+
127+
func reservedTypeSwitchLabel() {
128+
classImpl := &classImpl{}
129+
values := []int{}
130+
for i, v := range []interface{}{classImpl, 7, "string"} {
131+
switch t := v.(type) {
132+
case class:
133+
values = append(values, t.class_())
134+
default:
135+
values = append(values, i)
136+
}
137+
}
138+
fmt.Println(`reservedTypeSwitchLabel:`, values)
139+
140+
}

tests/testdata/reserved/main.out

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
reservedLoopLabel: [1 3 5 7]
2+
reservedGotoLabel: [1 2 3 4 5]
3+
reservedSwitchCaseLabel: [0 1 42]
4+
reservedSwitchLabelInCase: [99 99 42 3 4]
5+
reservedLabelledSwitch: [4]
6+
reservedLabelledBranch: [3]
7+
reservedSelectLabel: [42 1 2]
8+
reservedTypeSwitchLabel: [42 1 2]

0 commit comments

Comments
 (0)