This repository has been archived by the owner on Jul 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
/
rename.go
164 lines (150 loc) · 3.92 KB
/
rename.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"path/filepath"
"strings"
"rsc.io/c2go/cc"
)
var goKeyword = map[string]bool{
"chan": true,
"defer": true,
"fallthrough": true,
"func": true,
"go": true,
"import": true,
"interface": true,
"iota": true,
"map": true,
"package": true,
"range": true,
"select": true,
"type": true,
"var": true,
// not keywords but still need renaming
"fmt": true,
"path": true,
"rune": true,
"true": true,
"false": true,
}
// renameDecls renames file-local declarations to make them
// unique across the whole set of files being considered.
// For now, it appends the file base name to the declared name.
// Eventually it could be smarter and not do that when not necessary.
// It also renames names like 'type' and 'func' to avoid Go keywords.
func renameDecls(cfg *Config, prog *cc.Prog) {
// Rewrite C identifiers to avoid important Go words (keywords, iota, etc).
cc.Preorder(prog, func(x cc.Syntax) {
switch x := x.(type) {
case *cc.Decl:
if goKeyword[x.Name] {
// NOTE: Must put _ last so that name can be upper-cased for export.
x.Name += "_"
}
case *cc.Stmt:
for _, lab := range x.Labels {
if goKeyword[lab.Name] {
lab.Name += "_"
}
}
switch x.Op {
case cc.Goto:
if goKeyword[x.Text] {
x.Text += "_"
}
}
}
})
// Assign to packages (needed below but also in writeGoFiles).
for _, d := range prog.Decls {
if d.Body != nil && d.Body.Span.Start.File != "" {
d.Span = d.Body.Span
}
d.GoPackage = cfg.filePackage(d.Span.Start.File)
}
// Build list of declared top-level names.
// Not just prog.Decls because of enums and struct definitions.
typedefs := map[*cc.Type]bool{}
for _, d := range prog.Decls {
if d.Storage&cc.Typedef != 0 {
typedefs[d.Type] = true
}
}
var decls []*cc.Decl
for _, d := range prog.Decls {
if d.Name == "" {
if typedefs[d.Type] {
continue
}
switch d.Type.Kind {
case cc.Struct:
if d.Type.Tag != "" {
decls = append(decls, d)
d.Name = d.Type.Tag
d.Storage = cc.Typedef
}
if d.Type.TypeDecl == nil {
d.Type.TypeDecl = d
}
case cc.Enum:
d.Type.Tag = "" // enum tags are worthless
for _, dd := range d.Type.Decls {
decls = append(decls, dd)
}
}
continue
}
decls = append(decls, d)
if d.Storage&cc.Typedef != 0 && d.Type != nil && d.Type.TypeDecl == nil {
d.Type.TypeDecl = d
}
}
// Assign declarations to packages and identify conflicts.
count := make(map[string]int)
src := make(map[string]string)
for _, d := range decls {
// TODO(rsc): I don't understand why this is necessary given the above.
if d.Body != nil && d.Body.Span.Start.File != "" {
d.Span = d.Body.Span
}
d.GoPackage = cfg.filePackage(d.Span.Start.File)
key := d.GoPackage + "." + d.Name
if count[key]++; count[key] > 1 {
if d.Span.String() == src[key] {
// Assume this is a nested header and ignore duplicates.
count[key] = 1
continue
}
fprintf(d.Span, "conflicting name %s in %s (last at %s)", d.Name, d.GoPackage, src[key])
continue
}
src[key] = fmt.Sprintf("%s:%d", d.Span.Start.File, d.Span.Start.Line)
}
// Rename static, conflicting names.
for _, d := range decls {
key := d.GoPackage + "." + d.Name
if count[key] > 1 {
file := filepath.Base(d.Span.Start.File)
if i := strings.Index(file, "."); i >= 0 {
file = file[:i]
}
d.Name += "_" + file
}
if d.Type.Kind == cc.Func {
if d.Body != nil {
for _, s := range d.Body.Block {
if s.Op == cc.StmtDecl && s.Decl.Storage&cc.Static != 0 {
// Add function name as prefix.
// Will print at top level.
dd := s.Decl
dd.Name = d.Name + "_" + dd.Name
}
}
}
}
}
cfg.topDecls = decls
}