Skip to content

Commit

Permalink
[build] Enable string operations globalization code analyzers. (#879)
Browse files Browse the repository at this point in the history
Context: xamarin/xamarin-android#6271
Context: https://developercommunity.visualstudio.com/t/XamarinAndroid-binding-compiling-proble/1477963
Context: https://www.learncroatian.eu/blog/the-croatian-letters

If you attempt to build an Android Binding project on Windows within
a Bosnian, Croatian, or Serbian locale, the build may break as the
delegate type names created by 56955d9 may not be valid C#, e.g.:

	delegate IntPtr _JniMarshal_PP_Ljava/Lang/String; (IntPtr jnienv, IntPtr klass)

It *should* be declaringn a `_JniMarshal_PP_L` type, *not*
`_JniMarshal_PP_Ljava/Lang/String;`, the latter of which results in
numerous C# errors:

	error CS1003: Syntax error, '(' expected
	error CS1001: Identifier expected
	error CS1001: Identifier expected
	error CS1003: Syntax error, ',' expected
	error CS1003: Syntax error, ',' expected
	error CS1001: Identifier expected
	error CS1026: ) expected

The problem is caused by the interplay of two factors:

 1. Commit 56955d9 uses the culture-sensitive
    [`string.StartsWith(string)`][0] method to determine if a JNI
    type name starts with `L`:

        if (jni_name.StartsWith ("L") || jni_name.StartsWith ("["))
            return "L";

 2. In the `bs`, `hr`, and `sr` locales, the strings `Lj` and `lj`
    are treated as a single letter, *distinct from* `L` or `l`.
    In those locales, this expression is *false*, not true:
    
        "Ljava/lang/String;".StartsWith ("L") // false in bs, hr, sr; true everywhere else

Additionally, this issue only arises when Java package names
starting with `java` are used, e.g. `Ljava/lang/Object;`.  Java types
from packages that *don't* start with `java` don't encounter this bug.

Fix this issue by enabling the [CA1307][1] and [CA1309][2] rules,
previously disabled in commit ac914ce.  These code analysis rules
require the use of string methods which use the
[`StringComparison`][3] enumeration, for which we then specify
`StringComparison.Ordinal`, which is *not* culture-sensitive.

One complication with enabling these rules is that the .NET 6+
version of these rules are stricter and require overloads that do not
exist in .NET Framework or .NET Standard to fix the violations.
Enabling these rules in `.editorconfig` affects all
`$(TargetFrameworkMoniker)`s; we will instead use
`Directory.Build.props` to only enable them for non-.NET 6+ builds.

Finally, add a new `.yaml` step that shuts down the cached `dotnet`
MSBuild processes between invocations, to fix the error that has been
happening on Windows - NET Core:

	error MSB3027: Could not copy "obj\\Release\Java.Interop.BootstrapTasks.dll" to "D:\a\1\s\bin\BuildRelease\Java.Interop.BootstrapTasks.dll". Exceeded retry count of 10. Failed.  [D:\a\1\s\build-tools\Java.Interop.BootstrapTasks\Java.Interop.BootstrapTasks.csproj]
	error MSB3021: Unable to copy file "obj\\Release\Java.Interop.BootstrapTasks.dll" to "D:\a\1\s\bin\BuildRelease\Java.Interop.BootstrapTasks.dll". The process cannot access the file 'D:\a\1\s\bin\BuildRelease\Java.Interop.BootstrapTasks.dll' because it is being used by another process. [D:\a\1\s\build-tools\Java.Interop.BootstrapTasks\Java.Interop.BootstrapTasks.csproj]

[0]: https://docs.microsoft.com/en-us/dotnet/api/system.string.startswith?view=net-5.0#System_String_StartsWith_System_String_
[1]: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307
[2]: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1309
[3]: https://docs.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=net-5.0
  • Loading branch information
jpobst committed Sep 9, 2021
1 parent 3e6a623 commit 7068f4b
Show file tree
Hide file tree
Showing 45 changed files with 112 additions and 94 deletions.
4 changes: 2 additions & 2 deletions .editorconfig
Expand Up @@ -332,9 +332,9 @@ dotnet_diagnostic.CA1200.severity = none # Avoid using cref tags with a prefix
dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters
dotnet_diagnostic.CA1304.severity = none # Specify CultureInfo
dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider
dotnet_diagnostic.CA1307.severity = none # Specify StringComparison
#dotnet_diagnostic.CA1307.severity = none # Specify StringComparison - Controlled via Directory.Build.props
dotnet_diagnostic.CA1308.severity = none # Normalize strings to uppercase
dotnet_diagnostic.CA1309.severity = none # Use ordinal stringcomparison
#dotnet_diagnostic.CA1309.severity = none # Use ordinal stringcomparison - Controlled via Directory.Build.props
dotnet_diagnostic.CA1401.severity = none # P/Invokes should not be visible
dotnet_diagnostic.CA1417.severity = none # Do not use 'OutAttribute' on string parameters for P/Invokes
dotnet_diagnostic.CA1501.severity = none # Avoid excessive inheritance
Expand Down
11 changes: 10 additions & 1 deletion Directory.Build.props
Expand Up @@ -40,7 +40,7 @@
<AppendTargetFrameworkToOutputPath Condition=" '$(AppendTargetFrameworkToOutputPath)' == '' ">False</AppendTargetFrameworkToOutputPath>
<BaseIntermediateOutputPath Condition=" '$(BaseIntermediateOutputPath)' == '' ">obj\</BaseIntermediateOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<PropertyGroup Condition=" ( '$(TargetFramework)' != '' AND !$(TargetFramework.StartsWith('nets'))) AND (!$(TargetFramework.StartsWith('net4'))) ">
<JIBuildingForNetCoreApp>True</JIBuildingForNetCoreApp>
</PropertyGroup>
<PropertyGroup Condition=" '$(JIBuildingForNetCoreApp)' == 'True' ">
Expand Down Expand Up @@ -85,6 +85,15 @@
<_RunJNIEnvGen Condition=" '$(JIBuildingForNetCoreApp)' != 'True' ">$(Runtime) "$(_JNIEnvGenPath)"</_RunJNIEnvGen>
</PropertyGroup>

<!-- The net6.0 versions of these are stricter and require overloads not available in .NET Framework, so start with just .NET Framework -->
<PropertyGroup Condition=" '$(JIBuildingForNetCoreApp)' != 'True' ">
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<WarningsAsErrors>$(WarningsAsErrors);CA1307;CA1309;CA1310</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(JIBuildingForNetCoreApp)' == 'True' ">
<NoWarn>$(NoWarn);CA1307;CA1309;CA1310</NoWarn>
</PropertyGroup>

<!-- Add Roslyn analyzers NuGet to all projects -->
<ItemGroup Condition=" '$(DisableRoslynAnalyzers)' != 'True' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
Expand Down
7 changes: 7 additions & 0 deletions build-tools/automation/templates/core-build.yaml
Expand Up @@ -8,6 +8,13 @@ steps:
projects: Java.Interop.sln
arguments: '-c $(Build.Configuration) -target:Prepare -p:MaxJdkVersion=$(MaxJdkVersion)'

- task: DotNetCoreCLI@2
displayName: Shut down existing build server
inputs:
command: custom
custom: build-server
arguments: shutdown

- task: DotNetCoreCLI@2
displayName: Build Solution
inputs:
Expand Down
8 changes: 4 additions & 4 deletions build-tools/jnienv-gen/Generator.cs
Expand Up @@ -773,7 +773,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
{
if (managed != "IntPtr")
return new string [0];
var variableName = variable.StartsWith ("@")
var variableName = variable.StartsWith ("@", StringComparison.Ordinal)
? variable.Substring (1)
: variable;
return new[] {
Expand Down Expand Up @@ -851,7 +851,7 @@ public override string[] GetMarshalToManagedStatements (HandleStyle style, strin

public override string[] VerifyParameter (HandleStyle style, string variable)
{
var variableName = variable.StartsWith ("@")
var variableName = variable.StartsWith ("@", StringComparison.Ordinal)
? variable.Substring (1)
: variable;
return new[] {
Expand Down Expand Up @@ -940,7 +940,7 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string

public override string[] VerifyParameter (HandleStyle style, string variable)
{
var variableName = variable.StartsWith ("@")
var variableName = variable.StartsWith ("@", StringComparison.Ordinal)
? variable.Substring (1)
: variable;
switch (style) {
Expand Down Expand Up @@ -1097,7 +1097,7 @@ public override string[] GetMarshalToManagedStatements (HandleStyle style, strin

public override string[] VerifyParameter (HandleStyle style, string variable)
{
var variableName = variable.StartsWith ("@")
var variableName = variable.StartsWith ("@", StringComparison.Ordinal)
? variable.Substring (1)
: variable;
switch (style) {
Expand Down
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -24,7 +25,7 @@ public static List<ConstantEntry> FromEnumMapCsv (TextReader reader)
// Read the enum csv file
while ((s = reader.ReadLine ()) != null) {
// Skip empty lines and comments
if (string.IsNullOrEmpty (s) || s.StartsWith ("//"))
if (string.IsNullOrEmpty (s) || s.StartsWith ("//", StringComparison.Ordinal))
continue;

// Transient mode means remove the original field
Expand Down
Expand Up @@ -693,7 +693,7 @@ public Signature (string name, string signature, string connector, string manage
Name = name;

var jnisig = signature;
int closer = jnisig.IndexOf (")");
int closer = jnisig.IndexOf (')');
string ret = jnisig.Substring (closer + 1);
retval = JavaNativeTypeManager.Parse (ret).Type;
string jniparms = jnisig.Substring (1, closer - 1);
Expand Down
Expand Up @@ -112,10 +112,10 @@ static IEnumerable<XElement> GetParagraphs (ParseTreeNodeList children)
int len = 0;
int n = -1;

if ((n = s.IndexOf (UnixParagraph, i)) >= 0) {
if ((n = s.IndexOf (UnixParagraph, i, StringComparison.Ordinal)) >= 0) {
len = UnixParagraph.Length;
}
else if ((n = s.IndexOf (DosParagraph, i)) >= 0) {
else if ((n = s.IndexOf (DosParagraph, i, StringComparison.Ordinal)) >= 0) {
len = DosParagraph.Length;
}

Expand Down
Expand Up @@ -58,8 +58,8 @@ public static JniTypeName Parse (string jniType)

public static IEnumerable<JniTypeName> FromSignature (string signature)
{
if (signature.StartsWith ("(")) {
int e = signature.IndexOf (")");
if (signature.StartsWith ("(", StringComparison.Ordinal)) {
int e = signature.IndexOf (')');
signature = signature.Substring (1, e >= 0 ? e-1 : signature.Length-1);
}
int i = 0;
Expand Down Expand Up @@ -102,7 +102,7 @@ public static JniTypeName ReturnTypeFromSignature (string signature)
case 'J':
return new JniTypeName { Type = "long", IsKeyword = true };
case 'L': {
var e = signature.IndexOf (";", index);
var e = signature.IndexOf (';', index);
if (e <= 0)
throw new InvalidOperationException ("Missing reference type after 'L' at index " + i + "in: " + signature);
var s = index;
Expand Down
Expand Up @@ -67,7 +67,7 @@ static Stream FixAnnotationXML (Stream s)
// them up before loading with a validating XML parser.
var doc = new HtmlDocument ();
doc.Load (s);
if (doc.DocumentNode.FirstChild.InnerHtml.StartsWith ("<?xml"))
if (doc.DocumentNode.FirstChild.InnerHtml.StartsWith ("<?xml", StringComparison.Ordinal))
doc.DocumentNode.FirstChild.Remove ();

var ms = new MemoryStream ();
Expand Down
2 changes: 1 addition & 1 deletion src/Xamarin.Android.Tools.Bytecode/ClassPath.cs
Expand Up @@ -129,7 +129,7 @@ XAttribute GetPlatform ()

bool IsGeneratedName (string parameterName)
{
return parameterName.StartsWith ("p") && parameterName.Length > 1 && Char.IsDigit (parameterName [1]);
return parameterName.StartsWith ("p", StringComparison.Ordinal) && parameterName.Length > 1 && Char.IsDigit (parameterName [1]);
}

IEnumerable<ClassFile> GetDescendants (ClassFile theClass, IList<ClassFile> classFiles)
Expand Down
6 changes: 3 additions & 3 deletions src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs
Expand Up @@ -194,7 +194,7 @@ static void FixupExtensionMethod (MethodInfo method)
// like "$this$toByteString", we change it to "obj" to be a bit nicer.
var param = method.GetParameters ();

if (param.Length > 0 && param [0].Name.StartsWith ("$this$")) {
if (param.Length > 0 && param [0].Name.StartsWith ("$this$", StringComparison.Ordinal)) {
Log.Debug ($"Kotlin: Renaming extension parameter {method.DeclaringType?.ThisClass.Name.Value} - {method.Name} - {param [0].Name} -> obj");
param [0].Name = "obj";
}
Expand Down Expand Up @@ -288,7 +288,7 @@ static FieldInfo FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty p

static MethodInfo FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass)
{
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"get{property.Name}", true) == 0 &&
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"get{property.Name}", StringComparison.OrdinalIgnoreCase) == 0 &&
method.GetParameters ().Length == 0 &&
TypesMatch (method.ReturnType, property.ReturnType, kotlinClass));

Expand All @@ -297,7 +297,7 @@ static MethodInfo FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty

static MethodInfo FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass)
{
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"set{property.Name}", true) == 0 &&
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"set{property.Name}", StringComparison.OrdinalIgnoreCase) == 0 &&
property.ReturnType != null &&
method.GetParameters ().Length == 1 &&
method.ReturnType.BinaryName == "V" &&
Expand Down
6 changes: 3 additions & 3 deletions src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs
Expand Up @@ -57,7 +57,7 @@ public static ParameterInfo[] GetFilteredParameters (this MethodInfo method)
{
// Kotlin adds this to some constructors but I cannot tell which ones,
// so we'll just ignore them if we see them on the Java side
return method.GetParameters ().Where (p => p.Type.BinaryName != "Lkotlin/jvm/internal/DefaultConstructorMarker;" && !p.Name.StartsWith ("$")).ToArray ();
return method.GetParameters ().Where (p => p.Type.BinaryName != "Lkotlin/jvm/internal/DefaultConstructorMarker;" && !p.Name.StartsWith ("$", StringComparison.Ordinal)).ToArray ();
}

public static string GetMethodNameWithoutSuffix (this MethodInfo method)
Expand Down Expand Up @@ -102,9 +102,9 @@ public static bool IsDefaultConstructorMarker (this MethodInfo method)

public static bool IsPubliclyVisible (this KotlinPropertyFlags flags) => flags.HasFlag (KotlinPropertyFlags.Public) || flags.HasFlag (KotlinPropertyFlags.Protected);

public static bool IsUnnamedParameter (this ParameterInfo parameter) => parameter.Name.Length > 1 && parameter.Name.StartsWith ("p") && int.TryParse (parameter.Name.Substring (1), out var _);
public static bool IsUnnamedParameter (this ParameterInfo parameter) => parameter.Name.Length > 1 && parameter.Name.StartsWith ("p", StringComparison.Ordinal) && int.TryParse (parameter.Name.Substring (1), out var _);

public static bool IsUnnamedParameter (this KotlinValueParameter parameter) => parameter.Name.Length > 1 && parameter.Name.StartsWith ("p") && int.TryParse (parameter.Name.Substring (1), out var _);
public static bool IsUnnamedParameter (this KotlinValueParameter parameter) => parameter.Name.Length > 1 && parameter.Name.StartsWith ("p", StringComparison.Ordinal) && int.TryParse (parameter.Name.Substring (1), out var _);

static Dictionary<string, string> type_map = new Dictionary<string, string> {
{ "kotlin/Int", "I" },
Expand Down
2 changes: 1 addition & 1 deletion src/Xamarin.SourceWriter/Models/CommentWriter.cs
Expand Up @@ -16,7 +16,7 @@ public CommentWriter (string value)

public virtual void Write (CodeWriter writer)
{
if (Value.StartsWith ("#pragma"))
if (Value.StartsWith ("#pragma", StringComparison.Ordinal))
writer.WriteLineNoIndent (Value);
else
writer.WriteLine (Value);
Expand Down
Expand Up @@ -293,7 +293,7 @@ static Action A (Action a)
static string FormatFraction (double value, int width, int fractionWidth)
{
var v = value.ToString ("0.0" + new string ('#', fractionWidth - 1));
var i = v.IndexOf (NumberFormatInfo.CurrentInfo.NumberDecimalSeparator);
var i = v.IndexOf (NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, StringComparison.Ordinal);
var p = new string (' ', width - fractionWidth - i - 1);
return p + v + new string (' ', width - p.Length - v.Length);
}
Expand Down
Expand Up @@ -96,7 +96,7 @@ protected bool FileCompare (string file1, string file2)
using (var hash = new Crc64 ()) {
var f1hash = Convert.ToBase64String (hash.ComputeHash (f1));
var f2hash = Convert.ToBase64String (hash.ComputeHash (f2));
result = f1hash.Equals (f2hash);
result = string.Equals (f1hash, f2hash, StringComparison.Ordinal);
}
}

Expand Down
8 changes: 4 additions & 4 deletions tools/generator/CodeGenerationOptions.cs
Expand Up @@ -204,7 +204,7 @@ string GetJniTypeCode (ISymbol symbol)

var jni_name = symbol.JniName;

if (jni_name.StartsWith ("L") || jni_name.StartsWith ("["))
if (jni_name.StartsWith ("L", StringComparison.Ordinal) || jni_name.StartsWith ("[", StringComparison.Ordinal))
return "L";

return symbol.JniName;
Expand All @@ -221,9 +221,9 @@ public string GetOutputName (string type)
// Handle a few special cases
if (type == "System.Void")
return "void";
if (type.StartsWith ("params "))
if (type.StartsWith ("params ", StringComparison.Ordinal))
return "params " + GetOutputName (type.Substring ("params ".Length));
if (type.StartsWith ("global::"))
if (type.StartsWith ("global::", StringComparison.Ordinal))
Report.LogCodedErrorAndExit (Report.ErrorUnexpectedGlobal);
if (!UseGlobal)
return type;
Expand All @@ -249,7 +249,7 @@ public string GetSafeIdentifier (string name)
// Sadly that is not true in reality, so we need to exclude non-symbols
// when replacing the argument name with a valid identifier.
// (ReturnValue.ToNative() takes an argument which could be either an expression or mere symbol.)
if (name [name.Length-1] != ')' && !name.Contains ('.') && !name.StartsWith ("@")) {
if (name [name.Length-1] != ')' && !name.Contains ('.') && !name.StartsWith ("@", StringComparison.Ordinal)) {
if (!IdentifierValidator.IsValidIdentifier (name) ||
Array.BinarySearch (TypeNameUtilities.reserved_keywords, name) >= 0) {
name = name + "_";
Expand Down
4 changes: 2 additions & 2 deletions tools/generator/CodeGenerator.cs
Expand Up @@ -311,15 +311,15 @@ internal static void ProcessReferencedType (TypeDefinition td, CodeGenerationOpt
return;

// We want to exclude "IBlahInvoker" types from this type registration.
if (td.Name.EndsWith ("Invoker")) {
if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) {
string n = td.FullName;
n = n.Substring (0, n.Length - 7);
var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types;
if (types.Any (t => t.FullName == n))
return;
//Console.Error.WriteLine ("WARNING: " + td.FullName + " survived");
}
if (td.Name.EndsWith ("Implementor")) {
if (td.Name.EndsWith ("Implementor", StringComparison.Ordinal)) {
string n = td.FullName;
n = n.Substring (0, n.Length - 11);
var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types;
Expand Down
Expand Up @@ -877,7 +877,7 @@ public void WriteInterfaceInvoker (InterfaceGen @interface, string indent)

foreach (InterfaceGen iface in @interface.GetAllDerivedInterfaces ()) {
WriteInterfacePropertyInvokers (@interface, iface.Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), indent + "\t", members);
WriteInterfaceMethodInvokers (@interface, iface.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod && !@interface.IsCovariantMethod (m) && !(iface.FullName.StartsWith ("Java.Lang.ICharSequence") && m.Name.EndsWith ("Formatted"))), indent + "\t", members);
WriteInterfaceMethodInvokers (@interface, iface.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod && !@interface.IsCovariantMethod (m) && !(iface.FullName.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && m.Name.EndsWith ("Formatted", StringComparison.Ordinal))), indent + "\t", members);
if (iface.FullName == "Java.Lang.ICharSequence")
WriteCharSequenceEnumerator (indent + "\t");
}
Expand Down Expand Up @@ -923,7 +923,7 @@ public void WriteInterfaceListenerEventsAndProperties (InterfaceGen @interface,
foreach (var m in @interface.Methods) {
string nameSpec = @interface.Methods.Count > 1 ? m.EventName ?? m.AdjustedName : String.Empty;
string nameUnique = String.IsNullOrEmpty (nameSpec) ? name : nameSpec;
if (nameUnique.StartsWith ("On"))
if (nameUnique.StartsWith ("On", StringComparison.Ordinal))
nameUnique = nameUnique.Substring (2);
if (target.ContainsName (nameUnique))
nameUnique += "Event";
Expand Down Expand Up @@ -959,9 +959,9 @@ public void WriteInterfaceListenerEventsAndProperties (InterfaceGen @interface,
refs.Add (method.Name);
string rm = null;
string remove;
if (method.Name.StartsWith ("Set"))
if (method.Name.StartsWith ("Set", StringComparison.Ordinal))
remove = string.Format ("__v => {0} (null)", method.Name);
else if (method.Name.StartsWith ("Add") &&
else if (method.Name.StartsWith ("Add", StringComparison.Ordinal) &&
(rm = "Remove" + method.Name.Substring ("Add".Length)) != null &&
methods.Where (m => m.Name == rm).Any ())
remove = string.Format ("__v => {0} (__v)", rm);
Expand Down Expand Up @@ -990,8 +990,8 @@ public void WriteInterfaceListenerEventOrProperty (InterfaceGen @interface, Meth
if (m.EventName == string.Empty)
return;
string nameSpec = @interface.Methods.Count > 1 ? m.AdjustedName : String.Empty;
int idx = @interface.FullName.LastIndexOf (".");
int start = @interface.Name.StartsWith ("IOn") ? 3 : 1;
int idx = @interface.FullName.LastIndexOf ('.');
int start = @interface.Name.StartsWith ("IOn", StringComparison.Ordinal) ? 3 : 1;
string full_delegate_name = @interface.FullName.Substring (0, idx + 1) + @interface.Name.Substring (start, @interface.Name.Length - start - 8) + nameSpec;
if (m.IsSimpleEventHandler)
full_delegate_name = "EventHandler";
Expand Down Expand Up @@ -1586,7 +1586,7 @@ public void WriteProperty (Property property, GenBase gen, string indent, bool w
writer.WriteLine ("{0}}}", indent);
writer.WriteLine ();

if (property.Type.StartsWith ("Java.Lang.ICharSequence") && virtual_override != " override")
if (property.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && virtual_override != " override")
WritePropertyStringVariant (property, indent);
}

Expand Down Expand Up @@ -1631,7 +1631,7 @@ public void WritePropertyAbstractDeclaration (Property property, string indent,
}
writer.WriteLine ("{0}}}", indent);
writer.WriteLine ();
if (property.Type.StartsWith ("Java.Lang.ICharSequence"))
if (property.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal))
WritePropertyStringVariant (property, indent);
}

Expand Down
Expand Up @@ -87,7 +87,7 @@ static void DoParseJniMember (string jniMember, out string package, out string t
int endClass = jniMember.LastIndexOf ('.');

package = jniMember.Substring (0, endPackage).Replace ('/', '.');
if (package.StartsWith ("I:"))
if (package.StartsWith ("I:", StringComparison.Ordinal))
package = package.Substring (2);

if (endClass >= 0) {
Expand Down
Expand Up @@ -216,7 +216,7 @@ public static Method CreateMethod (GenBase declaringType, MethodDefinition m)
// Strip "Formatted" from ICharSequence-based method.
var name_base = method.IsReturnCharSequence ? m.Name.Substring (0, m.Name.Length - "Formatted".Length) : m.Name;

method.Name = m.IsGetter ? (m.Name.StartsWith ("get_Is") && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Get") + name_base.Substring (4) : m.IsSetter ? (m.Name.StartsWith ("set_Is") && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Set") + name_base.Substring (4) : name_base;
method.Name = m.IsGetter ? (m.Name.StartsWith ("get_Is", StringComparison.Ordinal) && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Get") + name_base.Substring (4) : m.IsSetter ? (m.Name.StartsWith ("set_Is", StringComparison.Ordinal) && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Set") + name_base.Substring (4) : name_base;

return method;
}
Expand Down

0 comments on commit 7068f4b

Please sign in to comment.