Skip to content

Commit 61cdb40

Browse files
[generator] Fix reserved keywords binary search (#977)
Context: 7068f4b Context: https://docs.microsoft.com/en-us/dotnet/core/extensions/performing-culture-insensitive-string-operations-in-arrays Commit 7068f4b enabled string code analyzers, because in e.g. the `sr` locale, `"Ljava".StartsWith("L")` would be *false*, because `Lj` was a language-specific digraph, and "special-cased". For intended behavior, we need to use `.StartsWith("L", StringComparison.Ordinal)`. There is a ["similar yet different" problem][0] with `Array.Sort()` and `Array.BinarySearch()` and string arrays: a locale-specific comparison is performed by default: var reserved_keywords = new [] { "as", "catch", "char", "checked", "class", "const", }; var index = Array.BinarySearch (reserved_keywords, "checked"); The *expectation* is that `index` is 3. In the `cs-CZ` locale, "ch" is a digraph, and `index` is -7, i.e. was not found. There is currently no Code Analysis check for this scenario. Review all `Array.Sort()` and `Array.BinarySearch()` invocations so that an appropriate `IComparer` instance is provided. This allows e.g. `checked` to be properly `@escaped` when created a binding in a machine with a `cs-CZ` locale. [0]: https://docs.microsoft.com/en-us/dotnet/core/extensions/performing-culture-insensitive-string-operations-in-arrays
1 parent 2a882d2 commit 61cdb40

File tree

4 files changed

+31
-5
lines changed

4 files changed

+31
-5
lines changed

tests/generator-Tests/Unit-Tests/CodeGenerationOptionsTests.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using MonoDroid.Generation;
34
using NUnit.Framework;
45

@@ -79,5 +80,17 @@ public void GetTypeReferenceName_Nullable ()
7980

8081
Assert.AreEqual ("uint", opt.GetTypeReferenceName (primitive_uint));
8182
}
83+
84+
[Test, TestCaseSource (nameof (ReservedKeywords))]
85+
[SetCulture ("cs-CZ")]
86+
public void GetSafeIdentifierCultureInvariant (string keyword)
87+
{
88+
var opt = new CodeGenerationOptions ();
89+
90+
Assert.AreEqual ($"{keyword}_", opt.GetSafeIdentifier (keyword));
91+
}
92+
93+
private static IEnumerable<TestCaseData> ReservedKeywords
94+
=> TypeNameUtilities.reserved_keywords.Select (keyword => new TestCaseData (keyword));
8295
}
8396
}

tests/generator-Tests/Unit-Tests/TypeNameUtilitiesTests.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using MonoDroid.Generation;
34
using NUnit.Framework;
45

@@ -19,5 +20,17 @@ public void MangleName ()
1920
Assert.AreEqual ("byte_var", TypeNameUtilities.MangleName ("byte_var"));
2021
Assert.AreEqual ("foo", TypeNameUtilities.MangleName ("foo"));
2122
}
23+
24+
[Test, TestCaseSource (nameof (ReservedKeywords))]
25+
[SetCulture ("cs-CZ")]
26+
public void MangleNameCutlureInvariant (string keyword)
27+
{
28+
Assert.AreEqual ($"@{keyword}", TypeNameUtilities.MangleName (keyword));
29+
}
30+
31+
private static IEnumerable<TestCaseData> ReservedKeywords
32+
=> TypeNameUtilities.reserved_keywords
33+
.Where (keyword => keyword != "event") // "event" is a special case which is mapped to "e" instead of "@event"
34+
.Select (keyword => new TestCaseData (keyword));
2235
}
2336
}

tools/generator/CodeGenerationOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ public string GetSafeIdentifier (string name)
267267
// (ReturnValue.ToNative() takes an argument which could be either an expression or mere symbol.)
268268
if (name [name.Length-1] != ')' && !name.Contains ('.') && !name.StartsWith ("@", StringComparison.Ordinal)) {
269269
if (!IdentifierValidator.IsValidIdentifier (name) ||
270-
Array.BinarySearch (TypeNameUtilities.reserved_keywords, name) >= 0) {
270+
Array.BinarySearch (TypeNameUtilities.reserved_keywords, name, StringComparer.Ordinal) >= 0) {
271271
name = name + "_";
272272
}
273273
}

tools/generator/Utilities/TypeNameUtilities.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ public static string MangleName (string name)
8080
{
8181
if (name == "event")
8282
return "e";
83-
84-
if (Array.BinarySearch (reserved_keywords, name) >= 0)
83+
84+
if (Array.BinarySearch (reserved_keywords, name, StringComparer.Ordinal) >= 0)
8585
return "@" + name;
8686

8787
return name;

0 commit comments

Comments
 (0)