@@ -117,6 +117,23 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
117
117
return pkg , nil
118
118
}
119
119
120
+ // Test if we find the '//gopherjs:keep_overridden' comment
121
+ func findKeepOverridenComment (doc * ast.CommentGroup ) bool {
122
+ if doc == nil {
123
+ return false
124
+ }
125
+ for _ , comment := range doc .List {
126
+ text := comment .Text
127
+ if i := strings .Index (text , " " ); i >= 0 {
128
+ text = text [:i ]
129
+ }
130
+ if text == "//gopherjs:keep_overridden" {
131
+ return true
132
+ }
133
+ }
134
+ return false
135
+ }
136
+
120
137
// parseAndAugment parses and returns all .go files of given pkg.
121
138
// Standard Go library packages are augmented with files in compiler/natives folder.
122
139
// If isTest is true and pkg.ImportPath has no _test suffix, package is built for running internal tests.
@@ -125,12 +142,19 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
125
142
// The native packages are augmented by the contents of natives.FS in the following way.
126
143
// The file names do not matter except the usual `_test` suffix. The files for
127
144
// native overrides get added to the package (even if they have the same name
128
- // as an existing file from the standard library). For all identifiers that exist
129
- // in the original AND the overrides, the original identifier in the AST gets
130
- // replaced by `_`. New identifiers that don't exist in original package get added.
145
+ // as an existing file from the standard library). For function identifiers that exist
146
+ // in the original AND the overrides AND that include the following directive in their comment:
147
+ // //gopherjs:keep_overridden, the original identifier in the AST gets prefixed by
148
+ // `_gopherjs_overridden_`. For other identifiers that exist in the original AND the overrides,
149
+ // the original identifier gets replaced by `_`. New identifiers that don't exist in original
150
+ // package get added.
131
151
func parseAndAugment (xctx XContext , pkg * PackageData , isTest bool , fileSet * token.FileSet ) ([]* ast.File , []JSFile , error ) {
132
152
var files []* ast.File
133
- replacedDeclNames := make (map [string ]bool )
153
+
154
+ type overrideInfo struct {
155
+ keepOverriden bool
156
+ }
157
+ replacedDeclNames := make (map [string ]overrideInfo )
134
158
pruneOriginalFuncs := make (map [string ]bool )
135
159
136
160
isXTest := strings .HasSuffix (pkg .ImportPath , "_test" )
@@ -170,18 +194,18 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
170
194
switch d := decl .(type ) {
171
195
case * ast.FuncDecl :
172
196
k := astutil .FuncKey (d )
173
- replacedDeclNames [k ] = true
197
+ replacedDeclNames [k ] = overrideInfo { keepOverriden : findKeepOverridenComment ( d . Doc )}
174
198
pruneOriginalFuncs [k ] = astutil .PruneOriginal (d )
175
199
case * ast.GenDecl :
176
200
switch d .Tok {
177
201
case token .TYPE :
178
202
for _ , spec := range d .Specs {
179
- replacedDeclNames [spec .(* ast.TypeSpec ).Name .Name ] = true
203
+ replacedDeclNames [spec .(* ast.TypeSpec ).Name .Name ] = overrideInfo {}
180
204
}
181
205
case token .VAR , token .CONST :
182
206
for _ , spec := range d .Specs {
183
207
for _ , name := range spec .(* ast.ValueSpec ).Names {
184
- replacedDeclNames [name .Name ] = true
208
+ replacedDeclNames [name .Name ] = overrideInfo {}
185
209
}
186
210
}
187
211
}
@@ -234,20 +258,26 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
234
258
switch d := decl .(type ) {
235
259
case * ast.FuncDecl :
236
260
k := astutil .FuncKey (d )
237
- if replacedDeclNames [k ] {
238
- d .Name = ast .NewIdent ("_" )
261
+ if info , ok := replacedDeclNames [k ]; ok {
239
262
if pruneOriginalFuncs [k ] {
240
263
// Prune function bodies, since it may contain code invalid for
241
264
// GopherJS and pin unwanted imports.
242
265
d .Body = nil
243
266
}
267
+ if info .keepOverriden {
268
+ // Allow overridden function calls
269
+ // The standard library implementation of foo() becomes _gopherjs_overridden_foo()
270
+ d .Name .Name = "_gopherjs_overridden_" + d .Name .Name
271
+ } else {
272
+ d .Name = ast .NewIdent ("_" )
273
+ }
244
274
}
245
275
case * ast.GenDecl :
246
276
switch d .Tok {
247
277
case token .TYPE :
248
278
for _ , spec := range d .Specs {
249
279
s := spec .(* ast.TypeSpec )
250
- if replacedDeclNames [s .Name .Name ] {
280
+ if _ , ok := replacedDeclNames [s .Name .Name ]; ok {
251
281
s .Name = ast .NewIdent ("_" )
252
282
s .Type = & ast.StructType {Struct : s .Pos (), Fields : & ast.FieldList {}}
253
283
s .TypeParams = nil
@@ -257,7 +287,7 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
257
287
for _ , spec := range d .Specs {
258
288
s := spec .(* ast.ValueSpec )
259
289
for i , name := range s .Names {
260
- if replacedDeclNames [name .Name ] {
290
+ if _ , ok := replacedDeclNames [name .Name ]; ok {
261
291
s .Names [i ] = ast .NewIdent ("_" )
262
292
}
263
293
}
0 commit comments