diff --git a/std/StringTools.hx b/std/StringTools.hx index d8efdd8b653..ea6f3923d69 100644 --- a/std/StringTools.hx +++ b/std/StringTools.hx @@ -464,7 +464,7 @@ class StringTools { #elseif java return (index < s.length) ? cast(_charAt(s, index), Int) : -1; #elseif js - return (cast s).charCodeAt(index); + return (cast s : js.lib.NativeString).charCodeAt(index); #elseif python return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index)); #elseif hl @@ -501,7 +501,7 @@ class StringTools { #elseif java return cast(_charAt(s, index), Int); #elseif js - return (cast s).charCodeAt(index); + return (cast s : js.lib.NativeString).charCodeAt(index); #elseif python return python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index)); #elseif hl diff --git a/std/js/_std/EReg.hx b/std/js/_std/EReg.hx index ae91f2ff697..c2323bbd212 100644 --- a/std/js/_std/EReg.hx +++ b/std/js/_std/EReg.hx @@ -19,6 +19,8 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +import js.lib.NativeString; + @:coreApi class EReg { var r:HaxeRegExp; @@ -84,7 +86,7 @@ } public inline function replace(s:String, by:String):String { - return (cast s).replace(r, by); + return (cast s : NativeString).replace(r, by); } public function map(s:String, f:EReg->String):String { @@ -112,7 +114,7 @@ } public static inline function escape(s:String):String { - return (cast s).replace(escapeRe, "\\$&"); + return (cast s : NativeString).replace(escapeRe, "\\$&"); } static var escapeRe = new js.lib.RegExp("[.*+?^${}()|[\\]\\\\]", "g"); diff --git a/std/js/_std/HxOverrides.hx b/std/js/_std/HxOverrides.hx index 8f55624dec0..e234c34864b 100644 --- a/std/js/_std/HxOverrides.hx +++ b/std/js/_std/HxOverrides.hx @@ -56,7 +56,7 @@ class HxOverrides { @:pure static function cca(s:String, index:Int):Null { - var x = (cast s).charCodeAt(index); + var x = (cast s : js.lib.NativeString).charCodeAt(index); if (x != x) // fast isNaN return js.Lib.undefined; // isNaN will still return true return x; diff --git a/std/js/lib/NativeString.hx b/std/js/lib/NativeString.hx new file mode 100644 index 00000000000..70664aa5f67 --- /dev/null +++ b/std/js/lib/NativeString.hx @@ -0,0 +1,34 @@ +package js.lib; + +/** + Native javascript string. +**/ +@:native("String") +extern class NativeString { + /** + The `charCodeAt()` method of String values returns an integer between 0 + and 65535 representing the UTF-16 code unit at the given index. + + If `index` is out of range of `0` – `str.length - 1`, returns `NaN`. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt + **/ + @:pure function charCodeAt(index:Int):Int; + + /** + The `replace()` method of String values returns a new string with one, + some, or all matches of a pattern replaced by a replacement. + + The pattern can be a `String` or a `js.lib.RegExp`, and the replacement + can be a string or a function called for each match. + + If pattern is a string, only the first occurrence will be replaced. The + original string is left unchanged. + + See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace + **/ + @:overload(function(pattern:RegExp, replacement:String):String {}) + @:overload(function(pattern:RegExp, replacement:String->String):String {}) + @:overload(function(pattern:String, replacement:String->String):String {}) + @:pure function replace(pattern:String, replacement:String):String; +} diff --git a/tests/server/src/cases/issues/Issue11904.hx b/tests/server/src/cases/issues/Issue11904.hx new file mode 100644 index 00000000000..388d7e7173c --- /dev/null +++ b/tests/server/src/cases/issues/Issue11904.hx @@ -0,0 +1,30 @@ +package cases.issues; + +import haxe.display.Diagnostic; + +class Issue11904 extends TestCase { + function test(_) { + vfs.putContent("Issue11904.hx", getTemplate("issues/Issue11904.hx")); + var args = ["-main", "Issue11904", "--js", "no.js", "--no-output"]; + runHaxe(args); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Issue11904.hx")}); + runHaxeJsonCb(args, DisplayMethods.Diagnostics, {file: new FsPath("Issue11904.hx")}, res -> { + Assert.equals(1, res.length); + Assert.equals(2, res[0].diagnostics.length); + + function check(d:Diagnostic) { + switch (d.kind) { + case ReplaceableCode: + Assert.equals("Unused variable", d.args.description); + + case _: + // trace(d); + Assert.fail("Unexpected diagnostics kind: " + d.kind); + } + } + + var diag = res[0].diagnostics; + for (d in diag) check(d); + }); + } +} diff --git a/tests/server/test/templates/issues/Issue11904.hx b/tests/server/test/templates/issues/Issue11904.hx new file mode 100644 index 00000000000..0a3fc17219c --- /dev/null +++ b/tests/server/test/templates/issues/Issue11904.hx @@ -0,0 +1,9 @@ +using StringTools; + +@:nullSafety +class Issue11904 { + static function main() {} + static function extractReturnType(hint:String):Void { + for (i => code in hint) {} + } +}