diff --git a/src/Xamarin.Android.Tools.Bytecode/Annotation.cs b/src/Xamarin.Android.Tools.Bytecode/Annotation.cs index 471e4bfda..fcde061a5 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Annotation.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Annotation.cs @@ -12,8 +12,8 @@ public sealed class Annotation ushort typeIndex; public string Type => ((ConstantPoolUtf8Item) ConstantPool [typeIndex]).Value; - public IList> - Values { get; } = new List> (); + public IList> + Values { get; } = new List> (); public Annotation (ConstantPool constantPool, Stream stream) { @@ -25,7 +25,7 @@ public Annotation (ConstantPool constantPool, Stream stream) var elementNameIndex = stream.ReadNetworkUInt16 (); var elementName = ((ConstantPoolUtf8Item) ConstantPool [elementNameIndex]).Value; var elementValue = AnnotationElementValue.Create (constantPool, stream); - Values.Add (new KeyValuePair (elementName, elementValue)); + Values.Add (new KeyValuePair (elementName, elementValue)); } } @@ -42,7 +42,7 @@ public override string ToString () values.Append ("}"); return $"Annotation('{Type}', {values})"; - void Append (KeyValuePair value) + void Append (KeyValuePair value) { values.Append (value.Key).Append (": "); values.Append (value.Value); diff --git a/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs b/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs index b2904faca..919b19813 100644 --- a/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs +++ b/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs @@ -9,9 +9,9 @@ namespace Xamarin.Android.Tools.Bytecode // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.16.1 public abstract class AnnotationElementValue { - public virtual string ToEncodedString () => ToString (); + public virtual string? ToEncodedString () => ToString (); - public static AnnotationElementValue Create (ConstantPool constantPool, Stream stream) + public static AnnotationElementValue? Create (ConstantPool constantPool, Stream stream) { var tag = stream.ReadNetworkByte (); @@ -38,8 +38,12 @@ public static AnnotationElementValue Create (ConstantPool constantPool, Stream s var values = new List (); - for (var i = 0; i < numValues; i++) - values.Add (Create (constantPool, stream)); + for (var i = 0; i < numValues; i++) { + var v = Create (constantPool, stream); + if (v == null) + continue; + values.Add (v); + } return new AnnotationElementArray { Values = values.ToArray () }; } @@ -79,49 +83,53 @@ public static AnnotationElementValue Create (ConstantPool constantPool, Stream s public class AnnotationElementEnum : AnnotationElementValue { - public string TypeName { get; set; } - public string ConstantName { get; set; } + public string? TypeName { get; set; } + public string? ConstantName { get; set; } public override string ToString () => $"Enum({TypeName}.{ConstantName})"; } public class AnnotationElementClassInfo : AnnotationElementValue { - public string ClassInfo { get; set; } + public string? ClassInfo { get; set; } - public override string ToString () => ClassInfo; + public override string? ToString () => ClassInfo; } public class AnnotationElementAnnotation : AnnotationElementValue { - public Annotation Annotation { get; set; } + public Annotation? Annotation { get; set; } - public override string ToString () => Annotation.ToString (); + public override string? ToString () => Annotation?.ToString (); } public class AnnotationElementArray : AnnotationElementValue { - public AnnotationElementValue[] Values { get; set; } + public AnnotationElementValue[]? Values { get; set; } - public override string ToString () => $"[{string.Join (", ", Values.Select (v => v.ToString ()))}]"; + public override string ToString () => Values == null + ? "[]" + : $"[{string.Join (", ", Values.Select (v => v.ToString ()))}]"; - public override string ToEncodedString () => $"[{string.Join (", ", Values.Select (v => v.ToEncodedString ()))}]"; + public override string? ToEncodedString () => Values == null + ? "[]" + : $"[{string.Join (", ", Values.Select (v => v.ToEncodedString ()))}]"; } public class AnnotationElementConstant : AnnotationElementValue { - public string Value { get; set; } + public string? Value { get; set; } - public override string ToString () => Value; + public override string? ToString () => Value; } public class AnnotationStringElementConstant : AnnotationElementConstant { public override string ToString () => $"\"{Value}\""; - public override string ToEncodedString () + public override string? ToEncodedString () { - return $"\"{Convert.ToBase64String (Encoding.UTF8.GetBytes (Value))}\""; + return $"\"{Convert.ToBase64String (Encoding.UTF8.GetBytes (Value ?? ""))}\""; } } } diff --git a/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs b/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs index fc7577af0..4dea58c21 100644 --- a/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs +++ b/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs @@ -26,10 +26,10 @@ public IEnumerable GetInfos (string name) return this.Where (a => a.Name == name); } - public T Get () + public T? Get () where T : AttributeInfo { - return (T) GetInfos (AttributeInfo.GetAttributeName()).SingleOrDefault (); + return (T?) GetInfos (AttributeInfo.GetAttributeName()).SingleOrDefault (); } } @@ -88,7 +88,7 @@ public string Name { internal static string GetAttributeName() { - string value; + string? value; if (AttributeNames.TryGetValue (typeof(T), out value)) { return value; } @@ -244,7 +244,7 @@ public ConstantPoolClassItem Class { get {return (ConstantPoolClassItem) ConstantPool [classIndex];} } - public ConstantPoolNameAndTypeItem Method { + public ConstantPoolNameAndTypeItem? Method { get {return methodIndex == 0 ? null : (ConstantPoolNameAndTypeItem) ConstantPool [methodIndex];} } @@ -351,7 +351,7 @@ public ConstantPoolClassItem OuterClass { get {return (ConstantPoolClassItem) ConstantPool [outerClassInfoIndex];} } - public string InnerName { + public string? InnerName { get { if (innerNameIndex == 0) // anonymous class @@ -360,7 +360,7 @@ public string InnerName { } } - public string OuterClassName => OuterClass?.Name?.Value; + public string? OuterClassName => OuterClass?.Name?.Value; public override string ToString () { @@ -447,7 +447,7 @@ public MethodParameterInfo (ConstantPool constantPool) ConstantPool = constantPool; } - public string Name { + public string? Name { get { if (nameIndex == 0) return null; diff --git a/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs b/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs index 66bbb6344..d49431f90 100644 --- a/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs +++ b/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -23,7 +24,7 @@ public sealed class ClassFile { public Methods Methods; public AttributeCollection Attributes; - ClassSignature signature; + ClassSignature? signature; public ClassFile (Stream stream) @@ -100,14 +101,17 @@ public string PackageName { public string FullJniName => "L" + ThisClass.Name.Value + ";"; - public string SourceFileName { + public string? SourceFileName { get { var sourceFile = Attributes.Get (); return sourceFile == null ? null : sourceFile.FileName; } } - public bool TryGetEnclosingMethodInfo (out string declaringClass, out string declaringMethod, out string declaringDescriptor) + public bool TryGetEnclosingMethodInfo ( + [NotNullWhen (true)] out string? declaringClass, + out string? declaringMethod, + out string? declaringDescriptor) { declaringClass = declaringMethod = declaringDescriptor = null; @@ -122,7 +126,7 @@ public bool TryGetEnclosingMethodInfo (out string declaringClass, out string dec return true; } - public ClassSignature GetSignature () + public ClassSignature? GetSignature () { if (this.signature != null) return this.signature; @@ -161,7 +165,7 @@ public IList InnerClasses { } } - public InnerClassInfo InnerClass { + public InnerClassInfo? InnerClass { get { return InnerClasses.SingleOrDefault (c => c.InnerClass == ThisClass); } @@ -189,7 +193,7 @@ public bool IsEnum { get {return (AccessFlags & ClassAccessFlags.Enum) != 0;} } - public override string ToString () => ThisClass?.Name.Value; + public override string? ToString () => ThisClass?.Name.Value; } [Flags] diff --git a/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs b/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs index 757190789..e8e8ccd9a 100644 --- a/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs +++ b/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs @@ -25,17 +25,17 @@ public class ClassPath { IList classFiles = new List (); - public string ApiSource { get; set; } + public string? ApiSource { get; set; } - public IEnumerable DocumentationPaths { get; set; } + public IEnumerable? DocumentationPaths { get; set; } - public string AndroidFrameworkPlatform { get; set; } + public string? AndroidFrameworkPlatform { get; set; } public bool AutoRename { get; set; } - public ClassPath (string path = null) + public ClassPath (string? path = null) { - if (string.IsNullOrEmpty (path)) + if (path == null || string.IsNullOrEmpty (path)) return; Load (path); @@ -138,14 +138,14 @@ public static bool IsJmodFile (string jmodFile) } } - XAttribute GetApiSource () + XAttribute? GetApiSource () { if (string.IsNullOrEmpty (ApiSource)) return null; return new XAttribute ("api-source", ApiSource); } - XAttribute GetPlatform () + XAttribute? GetPlatform () { if (string.IsNullOrEmpty (AndroidFrameworkPlatform)) return null; @@ -286,20 +286,27 @@ void FixupParametersFromDocs (XElement api, string path) var elements = api.XPathSelectElements ("./package/class[@visibility = 'public' or @visibility = 'protected']").ToList (); elements.AddRange (api.XPathSelectElements ("./package/interface[@visibility = 'public' or @visibility = 'protected']")); foreach (var elem in elements) { - var currentpackage = elem.Parent.Attribute ("name").Value; - var className = elem.Attribute ("name").Value; + var currentpackage = elem.Parent?.Attribute ("name")?.Value ?? ""; + var className = elem.Attribute ("name")?.Value; + + if (className == null) + continue; var methodsAndConstructors = elem.XPathSelectElements ("./method[@visibility = 'public' or @visibility = 'protected']").ToList (); methodsAndConstructors.AddRange (elem.XPathSelectElements ("./constructor[@visibility = 'public' or @visibility = 'protected']")); foreach (var method in methodsAndConstructors) { - var currentMethod = method.Attribute ("name").Value; + var currentMethod = method.Attribute ("name")?.Value; + if (currentMethod == null) + continue; var parameterElements = method.Elements ("parameter").ToList (); - if (!parameterElements.Select (x => x.Attribute ("name").Value).Any (p => IsGeneratedName (p))) + if (!parameterElements.Select (x => x.Attribute ("name")?.Value).Any (p => p != null && IsGeneratedName (p))) continue; - var parameters = parameterElements.Select (p => p.Attribute ("type").Value); + var parameters = parameterElements + .Select (p => p.Attribute ("type")?.Value!) + .Where (p => p != null); if (!parameters.Any ()) continue; @@ -308,7 +315,10 @@ void FixupParametersFromDocs (XElement api, string path) if (pnames == null || pnames.Length != parameterElements.Count) continue; for (int i = 0; i < parameterElements.Count; i++) { - parameterElements [i].Attribute ("name").Value = pnames [i]; + var a = parameterElements [i].Attribute ("name"); + if (a == null) + continue; + a.Value = pnames [i]; } } } diff --git a/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs b/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs index 57df19fd7..946898ec7 100644 --- a/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs +++ b/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs @@ -18,7 +18,7 @@ public ConstantPool (Stream stream) // indexes are one-based; // "The constant_pool table is indexed from 1 to constant_pool_count-1." - Add (null); + Add (null!); int constant_pool_count = stream.ReadNetworkUInt16 (); for (int i = 1; i < constant_pool_count; ++i) { var entry = ConstantPoolItem.CreateFromStream (this, stream); diff --git a/src/Xamarin.Android.Tools.Bytecode/Fields.cs b/src/Xamarin.Android.Tools.Bytecode/Fields.cs index 28f9685e1..ac13c5b00 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Fields.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Fields.cs @@ -33,7 +33,7 @@ public sealed class FieldInfo { public ConstantPool ConstantPool {get; private set;} public FieldAccessFlags AccessFlags {get; private set;} public AttributeCollection Attributes {get; private set;} - public string KotlinType { get; set; } + public string? KotlinType {get; set;} public FieldInfo (ConstantPool constantPool, Stream stream) { @@ -56,7 +56,7 @@ public string Descriptor { } } - public string GetSignature () + public string? GetSignature () { var signature = Attributes.Get (); return signature != null ? signature.Value : null; diff --git a/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs b/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs index d31cb2b9e..da57d29fe 100644 --- a/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs +++ b/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs @@ -55,13 +55,13 @@ public DroidDoc2Scraper (string dir) ShouldEscapeBrackets = true; } - string prev_path; - string [] prev_contents; + string? prev_path; + string[]? prev_contents; protected override IEnumerable GetContentLines (string path) { if (prev_path == path) - return prev_contents; + return prev_contents!; else { prev_path = path; string all = File.ReadAllText (path).Replace ('\r', ' ').Replace ('\n', ' '); @@ -123,8 +123,10 @@ public Java8DocScraper (string dir) protected override string StripTagsFromParameters (string value) { // Java8 javadoc contains possibly linked types with tags, so remove all of them. - while (value.IndexOf ('<') >= 0 && value.IndexOf ('>') > value.IndexOf ('<')) - value = value.Substring (0, value.IndexOf ('<')) + value.Substring (value.IndexOf ('>') + 1); + while (value.IndexOf ("<", StringComparison.Ordinal) >= 0 && + value.IndexOf (">", StringComparison.Ordinal) > value.IndexOf ("<", StringComparison.Ordinal)) + value = value.Substring (0, value.IndexOf ("<", StringComparison.Ordinal)) + + value.Substring (value.IndexOf (">", StringComparison.Ordinal) + 1); return value; } } @@ -132,21 +134,21 @@ protected override string StripTagsFromParameters (string value) public abstract class AndroidDocScraper : IJavaMethodParameterNameProvider { readonly String pattern_head; - readonly String reset_pattern_head; + readonly String? reset_pattern_head; readonly string [] parameter_pair_splitter; readonly bool continuous_param_lines; readonly String open_method; readonly String param_sep; readonly String close_method; - readonly String post_close_method_parens; + readonly String? post_close_method_parens; string root; - protected AndroidDocScraper (string dir, String patternHead, String resetPatternHead, String parameterPairSplitter, bool continuousParamLines) + protected AndroidDocScraper (string dir, String patternHead, String? resetPatternHead, String parameterPairSplitter, bool continuousParamLines) : this (dir, patternHead, resetPatternHead, parameterPairSplitter, continuousParamLines, "\\(", ", ", "\\)", null) { } - protected AndroidDocScraper (string dir, String patternHead, String resetPatternHead, String parameterPairSplitter, bool continuousParamLines, string openMethod, string paramSep, string closeMethod, string postCloseMethodParens) + protected AndroidDocScraper (string dir, String patternHead, String? resetPatternHead, String parameterPairSplitter, bool continuousParamLines, string openMethod, string paramSep, string closeMethod, string? postCloseMethodParens) { if (dir == null) throw new ArgumentNullException ("dir"); @@ -192,7 +194,7 @@ protected virtual string StripTagsFromParameters (string value) return value; } - public virtual String[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) + public virtual String[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) { string path = package.Replace ('.', '/') + '/' + type.Replace ('$', '.') + ".html"; string file = Path.Combine (root, path); @@ -212,8 +214,10 @@ public virtual String[] GetParameterNames (string package, string type, string m buffer.Append (param_sep); var ptype = ptypes [i]; if (ShouldEliminateGenericArguments) - while (ptype.IndexOf ('<') > 0 && ptype.IndexOf ('>') > ptype.IndexOf ('<')) - ptype = ptype.Substring (0, ptype.IndexOf ('<')) + ptype.Substring (ptype.IndexOf ('>') + 1); + while (ptype.IndexOf ("<", StringComparison.Ordinal) > 0 && + ptype.IndexOf (">", StringComparison.Ordinal) > ptype.IndexOf ("<", StringComparison.Ordinal)) + ptype = ptype.Substring (0, ptype.IndexOf ("<", StringComparison.Ordinal)) + + ptype.Substring (ptype.IndexOf (">", StringComparison.Ordinal) + 1); buffer.Append (ptype.Replace ('$', '.')); } if (ShouldEscapeBrackets) @@ -228,7 +232,7 @@ public virtual String[] GetParameterNames (string package, string type, string m try { String text = ""; - String prev = null; + String? prev = null; foreach (var _text in GetContentLines (file)) { text = _text.TrimEnd ('\r'); if (prev != null) @@ -262,25 +266,30 @@ public virtual String[] GetParameterNames (string package, string type, string m return null; } - static Dictionary> deprecatedFields; - static Dictionary> deprecatedMethods; + static Dictionary>? deprecatedFields; + static Dictionary>? deprecatedMethods; public static void LoadXml (String filename) { try { var doc = XDocument.Load (filename); + if (doc.Root == null) + return; deprecatedFields = new Dictionary> (); deprecatedMethods = new Dictionary> (); var files = doc.Root.Descendants ("file"); foreach (var file in files) { var f = new List (); - deprecatedFields [file.Attribute ("name").Value] = f; + var k = file.Attribute ("name")?.Value; + if (k == null) + continue; + deprecatedFields [k] = f; var fields = file.Descendants ("field"); foreach (var fld in fields) f.Add (fld.Value); var m = new List (); - deprecatedMethods [file.Attribute ("name").Value] = m; + deprecatedMethods [k] = m; var methods = file.Descendants ("method"); foreach (var meh in methods) m.Add (meh.Value); @@ -294,7 +303,7 @@ public static void LoadXml (String filename) public interface IJavaMethodParameterNameProvider { - String[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs); + String[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs); } public static class JavaMethodParameterNameProvider { @@ -305,7 +314,8 @@ public static JavaDocletType GetDocletType (string path) char[] buf = new char[500]; string packagesHtml = Path.Combine (path, "packages.html"); - if (File.Exists (packagesHtml) && File.ReadAllText (packagesHtml).Contains ("= 0) kind = JavaDocletType.DroidDoc2; string indexHtml = Path.Combine (path, "index.html"); @@ -313,22 +323,23 @@ public static JavaDocletType GetDocletType (string path) using (var reader = File.OpenText (indexHtml)) reader.ReadBlock (buf, 0, buf.Length); string rawHTML = new string (buf); - if (rawHTML.Contains ("Generated by javadoc (build 1.6")) + if (rawHTML.IndexOf ("Generated by javadoc (build 1.6", StringComparison.Ordinal) >= 0) kind = JavaDocletType.Java6; - else if (rawHTML.Contains ("Generated by javadoc (version 1.7")) + else if (rawHTML.IndexOf ("Generated by javadoc (version 1.7", StringComparison.Ordinal) >= 0) kind = JavaDocletType.Java7; - else if (rawHTML.Contains ("Generated by javadoc (1.8")) + else if (rawHTML.IndexOf ("Generated by javadoc (1.8", StringComparison.Ordinal) >= 0) kind = JavaDocletType.Java8; } // Check to see if it's an api.xml formatted doc if (File.Exists (path)) { - string rawXML = null; + string rawXML; using (var reader = File.OpenText (path)) { int len = reader.ReadBlock (buf, 0, buf.Length); rawXML = new string (buf, 0, len).Trim (); } - if (rawXML.Contains ("= 0 && + rawXML.IndexOf ("= 0) kind = JavaDocletType._ApiXml; else if (rawXML.StartsWith ("package", StringComparison.Ordinal) || rawXML.StartsWith (";", StringComparison.Ordinal)) { @@ -349,7 +360,7 @@ public ApiXmlDocScraper (string apiXmlFile) XDocument xdoc; - public string[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) + public string[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) { var methodOrCtor = method == "constructor" ? "constructor[" : $"method[@name='{method}'"; @@ -377,9 +388,11 @@ public string[] GetParameterNames (string package, string type, string method, s var methodElem = xdoc.XPathSelectElement (xpath.ToString ()); if (methodElem != null) - return methodElem.Elements ("parameter").Select (pe => pe.Attribute ("name")?.Value).ToArray (); + return methodElem.Elements ("parameter") + .Select (pe => pe.Attribute ("name")?.Value ?? "") + .ToArray (); - return new string[0]; + return null; } } } diff --git a/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs b/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs index 9f659a07a..16ead1973 100644 --- a/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs +++ b/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Xml.Linq; @@ -18,26 +19,26 @@ public JavaParameterNamesLoader(string path) class Parameter { - public string Type { get; set; } - public string Name { get; set; } + public string? Type { get; set; } + public string? Name { get; set; } } class Method { - public string Name { get; set; } - public List Parameters { get; set; } + public string? Name { get; set; } + public List? Parameters { get; set; } } class Type { - public string Name { get; set; } - public List Methods { get; set; } + public string? Name { get; set; } + public List? Methods { get; set; } } class Package { - public string Name { get; set; } - public List Types { get; set; } + public string? Name { get; set; } + public List? Types { get; set; } } // from https://github.com/atsushieno/xamarin-android-docimporter-ng/blob/master/Xamarin.Android.Tools.JavaStubImporter/JavaApiParameterNamesXmlExporter.cs#L78 @@ -70,14 +71,16 @@ class Package List LoadParameterFixupDescription (string path) { var fixup = new List (); - string package = null; + string? package = null; var types = new List (); - string type = null; + string? type = null; var methods = new List (); int currentLine = 0; foreach (var l in File.ReadAllLines (path)) { currentLine++; - var line = l.IndexOf (';') >= 0 ? l.Substring (0, l.IndexOf (';')).TrimEnd (' ', '\t') : l; + var line = l.IndexOf (";", StringComparison.Ordinal) >= 0 + ? l.Substring (0, l.IndexOf (";", StringComparison.Ordinal)).TrimEnd (' ', '\t') + : l; if (line.Trim ().Length == 0) continue; if (line.StartsWith ("package ", StringComparison.Ordinal)) { @@ -86,13 +89,13 @@ List LoadParameterFixupDescription (string path) fixup.Add (new Package { Name = package, Types = types }); continue; } else if (line.StartsWith (" ", StringComparison.Ordinal)) { - int open = line.IndexOf ('('); + int open = line.IndexOf ("(", StringComparison.Ordinal); if (open < 0) throw new ArgumentException ($"Unexpected line in {path} line {currentLine}: {line}"); string parameters = line.Substring (open + 1).TrimEnd (')'); string name = line.Substring (4, open - 4); if (name.FirstOrDefault () == '<') // generic method can begin with type parameters. - name = name.Substring (name.IndexOf (' ') + 1); + name = name.Substring (name.IndexOf (" ", StringComparison.Ordinal) + 1); methods.Add (new Method { Name = name, Parameters = parameters.Replace (", ", "\0").Split ('\0') @@ -100,10 +103,10 @@ List LoadParameterFixupDescription (string path) .Select (a => new Parameter { Type = string.Join (" ", a.Take (a.Length - 1)).Replace (",", ", "), Name = a.Last () }).ToList () }); } else { - type = line.Substring (line.IndexOf (' ', 2) + 1); + type = line.Substring (line.IndexOf (" ", 2, StringComparison.Ordinal) + 1); // To match type name from class-parse, we need to strip off generic arguments here (generics are erased). - if (type.IndexOf ('<') > 0) - type = type.Substring (0, type.IndexOf ('<')); + if (type.IndexOf ("<", StringComparison.Ordinal) > 0) + type = type.Substring (0, type.IndexOf ("<", StringComparison.Ordinal)); methods = new List (); types.Add (new Type { Name = type, Methods = methods }); } @@ -111,23 +114,25 @@ List LoadParameterFixupDescription (string path) return fixup; } - public string[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) + public string[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs) { var methods = this.packages - .Where(p => p.Name == package) - .SelectMany(p => p.Types) - .Where(t => t.Name == type) - .SelectMany(t => t.Methods) + .Where(p => p.Name == package && p.Types != null) + .SelectMany(p => p.Types!) + .Where(t => t.Name == type && t.Methods != null) + .SelectMany(t => t.Methods!) .Where(m => m.Name == method); var namedMethod = methods.FirstOrDefault (m => ParametersEqual (m.Parameters, ptypes)); if (namedMethod == null) return null; - return namedMethod.Parameters.Select (p => p.Name).ToArray (); + return namedMethod.Parameters?.Select (p => p.Name!).ToArray (); } - static bool ParametersEqual (List methodParameters, string[] ptypes) + static bool ParametersEqual (List? methodParameters, string[]? ptypes) { - if (methodParameters.Count != ptypes.Length) + if (methodParameters?.Count != ptypes?.Length) + return false; + if (methodParameters == null || ptypes == null) return false; for (int i = 0; i < ptypes.Length; ++i) { if (methodParameters[i].Type != ptypes [i]) diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs index 1b395fecb..d798192f7 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs @@ -12,18 +12,18 @@ namespace Xamarin.Android.Tools.Bytecode // https://github.com/JetBrains/kotlin/blob/master/core/metadata.jvm/src/jvm_metadata.proto public class KotlinFile { - public List Functions { get; set; } - public List Properties { get; set; } - public List TypeAliases { get; set; } - public KotlinTypeTable TypeTable { get; set; } - public KotlinVersionRequirementTable VersionRequirementTable { get; set; } + public List? Functions { get; set; } + public List? Properties { get; set; } + public List? TypeAliases { get; set; } + public KotlinTypeTable? TypeTable { get; set; } + public KotlinVersionRequirementTable? VersionRequirementTable { get; set; } internal static KotlinFile FromProtobuf (Package c, JvmNameResolver resolver) { return new KotlinFile { - Functions = c.Functions?.Select (f => KotlinFunction.FromProtobuf (f, resolver)).ToList (), - Properties = c.Properties?.Select (p => KotlinProperty.FromProtobuf (p, resolver)).ToList (), - TypeAliases = c.TypeAlias?.Select (tp => KotlinTypeAlias.FromProtobuf (tp, resolver)).ToList (), + Functions = c.Functions.ToList (resolver, KotlinFunction.FromProtobuf), + Properties = c.Properties.ToList (resolver, KotlinProperty.FromProtobuf), + TypeAliases = c.TypeAlias.ToList (resolver, KotlinTypeAlias.FromProtobuf), TypeTable = KotlinTypeTable.FromProtobuf (c.TypeTable, resolver), VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver) }; @@ -32,39 +32,39 @@ internal static KotlinFile FromProtobuf (Package c, JvmNameResolver resolver) public class KotlinClass : KotlinFile { - public string CompanionObjectName { get; set; } - public List Constructors { get; set; } - public List EnumEntries { get; set; } + public string? CompanionObjectName { get; set; } + public List? Constructors { get; set; } + public List? EnumEntries { get; set; } public KotlinClassFlags Flags { get; set; } - public string FullyQualifiedName { get; set; } + public string? FullyQualifiedName { get; set; } public KotlinClassInheritability Inheritability { get; set; } public List NestedClassNames { get; set; } = new List (); public KotlinClassType ObjectType { get; set; } - public List SealedSubclassFullyQualifiedNames { get; set; } - public List SuperTypeIds { get; set; } - public List SuperTypes { get; set; } - public List TypeParameters { get; set; } - public int [] VersionRequirements { get; set; } + public List? SealedSubclassFullyQualifiedNames { get; set; } + public List? SuperTypeIds { get; set; } + public List? SuperTypes { get; set; } + public List? TypeParameters { get; set; } + public int []? VersionRequirements { get; set; } public KotlinClassVisibility Visibility { get; set; } internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver) { return new KotlinClass { CompanionObjectName = c.CompanionObjectName > 0 ? resolver.GetString (c.CompanionObjectName) : null, - Constructors = c.Constructors?.Select (ctor => KotlinConstructor.FromProtobuf (ctor, resolver)).ToList (), + Constructors = c.Constructors.ToList (resolver, KotlinConstructor.FromProtobuf), EnumEntries = c.EnumEntries?.Select (e => resolver.GetString (e.Name)).ToList (), Flags = (KotlinClassFlags)c.Flags, FullyQualifiedName = c.FqName > 0 ? resolver.GetString (c.FqName) : null, - Functions = c.Functions?.Select (f => KotlinFunction.FromProtobuf (f, resolver)).ToList (), + Functions = c.Functions.ToList (resolver, KotlinFunction.FromProtobuf), Inheritability = (KotlinClassInheritability)((c.Flags & 0b110000) >> 4), - NestedClassNames = c.NestedClassNames?.Select (n => resolver.GetString (n)).ToList (), + NestedClassNames = c.NestedClassNames?.Select (n => resolver.GetString (n)).ToList () ?? new List (), ObjectType = (KotlinClassType) ((c.Flags & 0b111000000) >> 6), - Properties = c.Properties?.Select (p => KotlinProperty.FromProtobuf (p, resolver)).ToList (), + Properties = c.Properties.ToList (resolver, KotlinProperty.FromProtobuf), SealedSubclassFullyQualifiedNames = c.SealedSubclassFqNames?.Select (n => resolver.GetString (n)).ToList (), SuperTypeIds = c.SupertypeIds?.Select (n => resolver.GetString (n)).ToList (), - SuperTypes = c.Supertypes?.Select (st => KotlinType.FromProtobuf (st, resolver)).ToList (), - TypeAliases = c.TypeAlias?.Select (tp => KotlinTypeAlias.FromProtobuf (tp, resolver)).ToList (), - TypeParameters = c.TypeParameters?.Select (tp => KotlinTypeParameter.FromProtobuf (tp, resolver)).ToList (), + SuperTypes = c.Supertypes.ToList (resolver, KotlinType.FromProtobuf), + TypeAliases = c.TypeAlias.ToList (resolver, KotlinTypeAlias.FromProtobuf), + TypeParameters = c.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), VersionRequirements = c.VersionRequirements, TypeTable = KotlinTypeTable.FromProtobuf (c.TypeTable, resolver), VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver), @@ -75,7 +75,7 @@ internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver) public class KotlinMethodBase { - public int [] VersionRequirements { get; set; } + public int []? VersionRequirements { get; set; } public virtual string GetSignature () => string.Empty; } @@ -83,39 +83,39 @@ public class KotlinMethodBase public class KotlinConstructor : KotlinMethodBase { public KotlinConstructorFlags Flags { get; set; } - public List ValueParameters { get; set; } + public List? ValueParameters { get; set; } - internal static KotlinConstructor FromProtobuf (Constructor c, JvmNameResolver resolver) + internal static KotlinConstructor? FromProtobuf (Constructor c, JvmNameResolver resolver) { if (c is null) return null; return new KotlinConstructor { Flags = (KotlinConstructorFlags)c.Flags, - ValueParameters = c.ValueParameters?.Select (vp => KotlinValueParameter.FromProtobuf (vp, resolver)).ToList (), + ValueParameters = c.ValueParameters.ToList (resolver, KotlinValueParameter.FromProtobuf), VersionRequirements = c.VersionRequirements }; } public override string GetSignature () { - return $"({ValueParameters.GetSignature ()})V"; + return $"({ValueParameters?.GetSignature ()})V"; } } public class KotlinAnnotation { public int Id { get; set; } - public List Arguments { get; set; } + public List? Arguments { get; set; } - internal static KotlinAnnotation FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation a, JvmNameResolver resolver) + internal static KotlinAnnotation? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation a, JvmNameResolver resolver) { if (a is null) return null; return new KotlinAnnotation { Id = a.Id, - Arguments = a.Arguments?.Select (vp => KotlinAnnotationArgument.FromProtobuf (vp, resolver)).ToList () + Arguments = a.Arguments.ToList (resolver, KotlinAnnotationArgument.FromProtobuf), }; } } @@ -123,9 +123,9 @@ internal static KotlinAnnotation FromProtobuf (org.jetbrains.kotlin.metadata.jvm public class KotlinAnnotationArgument { public int NameId { get; set; } - public KotlinAnnotationArgumentValue Value { get; set; } + public KotlinAnnotationArgumentValue? Value { get; set; } - internal static KotlinAnnotationArgument FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument a, JvmNameResolver resolver) + internal static KotlinAnnotationArgument? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument a, JvmNameResolver resolver) { if (a is null) return null; @@ -143,15 +143,15 @@ public class KotlinAnnotationArgumentValue public long IntValue { get; set; } public float FloatValue { get; set; } public double DoubleValue { get; set; } - public string StringValue { get; set; } + public string? StringValue { get; set; } public int ClassId { get; set; } public int EnumValueId { get; set; } - public KotlinAnnotation Annotation { get; set; } - public List ArrayElements { get; set; } + public KotlinAnnotation? Annotation { get; set; } + public List? ArrayElements { get; set; } public int ArrayDimensionCount { get; set; } public KotlinAnnotationFlags Flags { get; set; } - internal static KotlinAnnotationArgumentValue FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument.Value value, JvmNameResolver resolver) + internal static KotlinAnnotationArgumentValue? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument.Value value, JvmNameResolver resolver) { if (value is null) return null; @@ -166,7 +166,7 @@ internal static KotlinAnnotationArgumentValue FromProtobuf (org.jetbrains.kotlin EnumValueId = value.EnumValueId, Annotation = KotlinAnnotation.FromProtobuf (value.Annotation, resolver), ArrayDimensionCount = value.ArrayDimensionCount, - ArrayElements = value.ArrayElements?.Select (vp => KotlinAnnotationArgumentValue.FromProtobuf (vp, resolver)).ToList (), + ArrayElements = value.ArrayElements.ToList (resolver,KotlinAnnotationArgumentValue.FromProtobuf), Flags = (KotlinAnnotationFlags)value.Flags }; } @@ -175,18 +175,18 @@ internal static KotlinAnnotationArgumentValue FromProtobuf (org.jetbrains.kotlin public class KotlinEffect { public KotlinEffectType EffectType { get; set; } - public List EffectConstructorArguments { get; set; } - public KotlinExpression ConclusionOfConditionalEffect { get; set; } + public List? EffectConstructorArguments { get; set; } + public KotlinExpression? ConclusionOfConditionalEffect { get; set; } public KotlinInvocationKind Kind { get; set; } - internal static KotlinEffect FromProtobuf (Effect ef, JvmNameResolver resolver) + internal static KotlinEffect? FromProtobuf (Effect ef, JvmNameResolver resolver) { if (ef is null) return null; return new KotlinEffect { EffectType = (KotlinEffectType) ef.effect_type, - EffectConstructorArguments = ef.EffectConstructorArguments?.Select (vp => KotlinExpression.FromProtobuf (vp, resolver)).ToList (), + EffectConstructorArguments = ef.EffectConstructorArguments.ToList (resolver, KotlinExpression.FromProtobuf), ConclusionOfConditionalEffect = KotlinExpression.FromProtobuf (ef.ConclusionOfConditionalEffect, resolver), Kind = (KotlinInvocationKind) ef.Kind }; @@ -198,12 +198,12 @@ public class KotlinExpression public KotlinExpressionFlags Flags { get; set; } public int ValueParameterReference { get; set; } public KotlinConstantValue ConstantValue { get; set; } - public KotlinType IsInstanceType { get; set; } + public KotlinType? IsInstanceType { get; set; } public int IsInstanceTypeId { get; set; } - public List AndArguments { get; set; } - public List OrArguments { get; set; } + public List? AndArguments { get; set; } + public List? OrArguments { get; set; } - internal static KotlinExpression FromProtobuf (Expression exp, JvmNameResolver resolver) + internal static KotlinExpression? FromProtobuf (Expression exp, JvmNameResolver resolver) { if (exp is null) return null; @@ -214,28 +214,28 @@ internal static KotlinExpression FromProtobuf (Expression exp, JvmNameResolver r ConstantValue = (KotlinConstantValue) exp.constant_value, IsInstanceType = KotlinType.FromProtobuf (exp.IsInstanceType, resolver), IsInstanceTypeId = exp.IsInstanceTypeId, - AndArguments = exp.AndArguments?.Select (tp => KotlinExpression.FromProtobuf (tp, resolver)).ToList (), - OrArguments = exp.OrArguments?.Select (vp => KotlinExpression.FromProtobuf (vp, resolver)).ToList () + AndArguments = exp.AndArguments.ToList (resolver, KotlinExpression.FromProtobuf), + OrArguments = exp.OrArguments.ToList (resolver, KotlinExpression.FromProtobuf), }; } } public class KotlinFunction : KotlinMethodBase { - public string Name { get; set; } - public string JvmName { get; set; } - public string JvmSignature { get; set; } + public string? Name { get; set; } + public string? JvmName { get; set; } + public string? JvmSignature { get; set; } public KotlinFunctionFlags Flags { get; set; } - public KotlinType ReturnType { get; set; } + public KotlinType? ReturnType { get; set; } public int ReturnTypeId { get; set; } - public List TypeParameters { get; set; } - public KotlinType ReceiverType { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? ReceiverType { get; set; } public int ReceiverTypeId { get; set; } - public KotlinTypeTable TypeTable { get; set; } - public KotlinContract Contract { get; set; } - public List ValueParameters { get; set; } + public KotlinTypeTable? TypeTable { get; set; } + public KotlinContract? Contract { get; set; } + public List? ValueParameters { get; set; } - internal static KotlinFunction FromProtobuf (Function f, JvmNameResolver resolver) + internal static KotlinFunction? FromProtobuf (Function f, JvmNameResolver resolver) { if (f is null) return null; @@ -245,19 +245,19 @@ internal static KotlinFunction FromProtobuf (Function f, JvmNameResolver resolve return new KotlinFunction { Flags = (KotlinFunctionFlags)f.Flags, Name = resolver.GetString (f.Name), - JvmName = resolver.GetString ((sig?.Name ?? 0) > 0 ? sig.Name : f.Name), + JvmName = resolver.GetString ((sig is null || sig.Name == 0) ? f.Name : sig.Name), JvmSignature = sig is null ? null : resolver.GetString (sig.Desc), ReturnType = KotlinType.FromProtobuf (f.ReturnType, resolver), ReturnTypeId = f.ReturnTypeId, ReceiverType = KotlinType.FromProtobuf (f.ReceiverType, resolver), ReceiverTypeId = f.ReceiverTypeId, - TypeParameters = f.TypeParameters?.Select (tp => KotlinTypeParameter.FromProtobuf (tp, resolver)).ToList (), - ValueParameters = f.ValueParameters?.Select (vp => KotlinValueParameter.FromProtobuf (vp, resolver)).ToList (), + TypeParameters = f.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), + ValueParameters = f.ValueParameters.ToList (resolver, KotlinValueParameter.FromProtobuf), VersionRequirements = f.VersionRequirements }; } - public override string ToString () => Name; + public override string? ToString () => Name; public string GetFlags () { @@ -274,30 +274,30 @@ public string GetFlags () public class KotlinContract { - public List Effects { get; set; } + public List? Effects { get; set; } - internal static KotlinContract FromProtobuf (Contract c, JvmNameResolver resolver) + internal static KotlinContract? FromProtobuf (Contract c, JvmNameResolver resolver) { return new KotlinContract { - Effects = c.Effects?.Select (tp => KotlinEffect.FromProtobuf (tp, resolver)).ToList () + Effects = c.Effects.ToList (resolver, KotlinEffect.FromProtobuf), }; } } public class KotlinProperty : KotlinMethodBase { - public string Name { get; set; } + public string? Name { get; set; } public KotlinPropertyFlags Flags { get; set; } - public KotlinType ReturnType { get; set; } + public KotlinType? ReturnType { get; set; } public int ReturnTypeId { get; set; } - public List TypeParameters { get; set; } - public KotlinType ReceiverType { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? ReceiverType { get; set; } public int ReceiverTypeId { get; set; } - public KotlinValueParameter SetterValueParameter { get; set; } + public KotlinValueParameter? SetterValueParameter { get; set; } public int GetterFlags { get; set; } public int SetterFlags { get; set; } - internal static KotlinProperty FromProtobuf (Property p, JvmNameResolver resolver) + internal static KotlinProperty? FromProtobuf (Property p, JvmNameResolver resolver) { if (p is null) return null; @@ -312,38 +312,38 @@ internal static KotlinProperty FromProtobuf (Property p, JvmNameResolver resolve SetterValueParameter = KotlinValueParameter.FromProtobuf (p.SetterValueParameter, resolver), GetterFlags = p.GetterFlags, SetterFlags = p.SetterFlags, - TypeParameters = p.TypeParameters?.Select (tp => KotlinTypeParameter.FromProtobuf (tp, resolver)).ToList (), + TypeParameters = p.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), VersionRequirements = p.VersionRequirements }; } - public override string ToString () => Name; + public override string? ToString () => Name; } public class KotlinType { - public List Arguments { get; set; } + public List? Arguments { get; set; } public bool Nullable { get; set; } public int? FlexibleTypeCapabilitiesId { get; set; } - public KotlinType FlexibleUpperBound { get; set; } + public KotlinType? FlexibleUpperBound { get; set; } public int FlexibleUpperBoundId { get; set; } - public string ClassName { get; set; } + public string? ClassName { get; set; } public int? TypeParameter { get; set; } - public string TypeParameterName { get; set; } - public string TypeAliasName { get; set; } - public KotlinType OuterType { get; set; } + public string? TypeParameterName { get; set; } + public string? TypeAliasName { get; set; } + public KotlinType? OuterType { get; set; } public int? OuterTypeId { get; set; } - public KotlinType AbbreviatedType { get; set; } + public KotlinType? AbbreviatedType { get; set; } public int? AbbreviatedTypeId { get; set; } public KotlinTypeFlags Flags { get; set; } - internal static KotlinType FromProtobuf (Type t, JvmNameResolver resolver) + internal static KotlinType? FromProtobuf (Type t, JvmNameResolver resolver) { if (t is null) return null; return new KotlinType { - Arguments = t.Arguments?.Select (a => KotlinTypeArgument.FromProtobuf (a, resolver)).ToList (), + Arguments = t.Arguments.ToList (resolver, KotlinTypeArgument.FromProtobuf), Nullable = t.Nullable, FlexibleTypeCapabilitiesId = t.FlexibleTypeCapabilitiesId, FlexibleUpperBound = FromProtobuf (t.FlexibleUpperBound, resolver), @@ -367,16 +367,16 @@ public string GetSignature () public class KotlinTypeAlias { public int Flags { get; set; } - public string Name { get; set; } - public List TypeParameters { get; set; } - public KotlinType UnderlyingType { get; set; } + public string? Name { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? UnderlyingType { get; set; } public int UnderlyingTypeId { get; set; } - public KotlinType ExpandedType { get; set; } + public KotlinType? ExpandedType { get; set; } public int ExpandedTypeId { get; set; } - public List Annotations { get; set; } - public int [] VersionRequirements { get; set; } + public List? Annotations { get; set; } + public int []? VersionRequirements { get; set; } - internal static KotlinTypeAlias FromProtobuf (TypeAlias ta, JvmNameResolver resolver) + internal static KotlinTypeAlias? FromProtobuf (TypeAlias ta, JvmNameResolver resolver) { if (ta is null) return null; @@ -384,7 +384,7 @@ internal static KotlinTypeAlias FromProtobuf (TypeAlias ta, JvmNameResolver reso return new KotlinTypeAlias { Flags = ta.Flags, Name = resolver.GetString (ta.Name), - TypeParameters = ta.TypeParameters?.Select (tp => KotlinTypeParameter.FromProtobuf (tp, resolver)).ToList (), + TypeParameters = ta.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), UnderlyingType = KotlinType.FromProtobuf (ta.UnderlyingType, resolver), UnderlyingTypeId = ta.UnderlyingTypeId, ExpandedType = KotlinType.FromProtobuf (ta.ExpandedType, resolver), @@ -397,10 +397,10 @@ internal static KotlinTypeAlias FromProtobuf (TypeAlias ta, JvmNameResolver reso public class KotlinTypeArgument { public KotlinProjection Projection { get; set; } - public KotlinType Type { get; set; } + public KotlinType? Type { get; set; } public int TypeId { get; set; } - internal static KotlinTypeArgument FromProtobuf (Type.Argument ta, JvmNameResolver resolver) + internal static KotlinTypeArgument? FromProtobuf (Type.Argument ta, JvmNameResolver resolver) { if (ta is null) return null; @@ -416,13 +416,13 @@ internal static KotlinTypeArgument FromProtobuf (Type.Argument ta, JvmNameResolv public class KotlinTypeParameter { public int Id { get; set; } - public string Name { get; set; } + public string? Name { get; set; } public bool Reified { get; set; } public KotlinVariance Variance { get; set; } - public List UpperBounds { get; set; } - public int [] UpperBoundsIds { get; set; } + public List? UpperBounds { get; set; } + public int []? UpperBoundsIds { get; set; } - internal static KotlinTypeParameter FromProtobuf (TypeParameter vp, JvmNameResolver resolver) + internal static KotlinTypeParameter? FromProtobuf (TypeParameter vp, JvmNameResolver resolver) { if (vp is null) return null; @@ -432,7 +432,7 @@ internal static KotlinTypeParameter FromProtobuf (TypeParameter vp, JvmNameResol Name = resolver.GetString (vp.Name), Reified = vp.Reified, Variance = (KotlinVariance) vp.variance, - UpperBounds = vp.UpperBounds?.Select (ub => KotlinType.FromProtobuf (ub, resolver)).ToList (), + UpperBounds = vp.UpperBounds.ToList (resolver, KotlinType.FromProtobuf), UpperBoundsIds = vp.UpperBoundIds }; } @@ -440,16 +440,16 @@ internal static KotlinTypeParameter FromProtobuf (TypeParameter vp, JvmNameResol public class KotlinTypeTable { - public List Types { get; set; } + public List? Types { get; set; } public int FirstNullable { get; set; } - internal static KotlinTypeTable FromProtobuf (TypeTable ta, JvmNameResolver resolver) + internal static KotlinTypeTable? FromProtobuf (TypeTable ta, JvmNameResolver resolver) { if (ta is null) return null; return new KotlinTypeTable { - Types = ta.Types?.Select (t => KotlinType.FromProtobuf (t, resolver)).ToList (), + Types = ta.Types.ToList (resolver, KotlinType.FromProtobuf), FirstNullable = ta.FirstNullable }; } @@ -464,7 +464,7 @@ public class KotlinVersionRequirement public int Message { get; set; } public KotlinVersionKind VersionKind { get; set; } - internal static KotlinVersionRequirement FromProtobuf (VersionRequirement vr, JvmNameResolver resolver) + internal static KotlinVersionRequirement? FromProtobuf (VersionRequirement vr, JvmNameResolver resolver) { if (vr is null) return null; @@ -482,15 +482,15 @@ internal static KotlinVersionRequirement FromProtobuf (VersionRequirement vr, Jv public class KotlinVersionRequirementTable { - public List Requirements { get; set; } + public List? Requirements { get; set; } - internal static KotlinVersionRequirementTable FromProtobuf (VersionRequirementTable vrt, JvmNameResolver resolver) + internal static KotlinVersionRequirementTable? FromProtobuf (VersionRequirementTable vrt, JvmNameResolver resolver) { if (vrt is null) return null; return new KotlinVersionRequirementTable { - Requirements = vrt.Requirements?.Select (t => KotlinVersionRequirement.FromProtobuf (t, resolver)).ToList () + Requirements = vrt.Requirements.ToList (resolver, KotlinVersionRequirement.FromProtobuf), }; } } @@ -498,13 +498,13 @@ internal static KotlinVersionRequirementTable FromProtobuf (VersionRequirementTa public class KotlinValueParameter { public KotlinParameterFlags Flags { get; set; } - public string Name { get; set; } - public KotlinType Type { get; set; } + public string? Name { get; set; } + public KotlinType? Type { get; set; } public int TypeId { get; set; } - public KotlinType VarArgElementType { get; set; } + public KotlinType? VarArgElementType { get; set; } public int VarArgElementTypeId { get; set; } - internal static KotlinValueParameter FromProtobuf (ValueParameter vp, JvmNameResolver resolver) + internal static KotlinValueParameter? FromProtobuf (ValueParameter vp, JvmNameResolver resolver) { if (vp is null) return null; @@ -519,7 +519,7 @@ internal static KotlinValueParameter FromProtobuf (ValueParameter vp, JvmNameRes }; } - public string GetSignature () => Type.GetSignature (); + public string? GetSignature () => Type?.GetSignature (); } public enum KotlinVariance diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs index 372c48a72..a763718f4 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs @@ -34,6 +34,8 @@ public static void Fixup (IList classes) if (!c.AccessFlags.IsPubliclyVisible ()) continue; + if (class_metadata.Constructors == null) + continue; foreach (var con in class_metadata.Constructors) FixupConstructor (FindJavaConstructor (class_metadata, con, c), con); @@ -44,16 +46,21 @@ public static void Fixup (IList classes) // used for generic type resolution if available for class types) FixupJavaMethods (c.Methods); - foreach (var met in metadata.Functions) - FixupFunction (FindJavaMethod (metadata, met, c), met, class_metadata); + if (metadata.Functions != null) { + foreach (var met in metadata.Functions) + FixupFunction (FindJavaMethod (metadata, met, c), met, class_metadata); + } + - foreach (var prop in metadata.Properties) { - var getter = FindJavaPropertyGetter (metadata, prop, c); - var setter = FindJavaPropertySetter (metadata, prop, c); + if (metadata.Properties != null) { + foreach (var prop in metadata.Properties) { + var getter = FindJavaPropertyGetter (metadata, prop, c); + var setter = FindJavaPropertySetter (metadata, prop, c); - FixupProperty (getter, setter, prop); + FixupProperty (getter, setter, prop); - FixupField (FindJavaFieldProperty (metadata, prop, c), prop); + FixupField (FindJavaFieldProperty (metadata, prop, c), prop); + } } } catch (Exception ex) { @@ -128,7 +135,7 @@ static void FixupJavaMethods (Methods methods) // not just ones that have corresponding Kotlin metadata, like FixupFunction does. // Hide Kotlin generated methods like "add-impl" that aren't intended for end users - foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.Name.Contains ("-impl"))) { + foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.Name.IndexOf ("-impl", StringComparison.Ordinal) >= 0)) { Log.Debug ($"Kotlin: Hiding implementation method {method.DeclaringType?.ThisClass.Name.Value} - {method.Name}"); method.AccessFlags = MethodAccessFlags.Private; } @@ -144,7 +151,7 @@ static void FixupJavaMethods (Methods methods) FixupExtensionMethod (method); } - static void FixupConstructor (MethodInfo method, KotlinConstructor metadata) + static void FixupConstructor (MethodInfo? method, KotlinConstructor metadata) { if (method is null) return; @@ -156,7 +163,7 @@ static void FixupConstructor (MethodInfo method, KotlinConstructor metadata) } } - static void FixupFunction (MethodInfo method, KotlinFunction metadata, KotlinClass kotlinClass) + static void FixupFunction (MethodInfo? method, KotlinFunction metadata, KotlinClass? kotlinClass) { if (method is null || !method.IsPubliclyVisible) return; @@ -172,7 +179,9 @@ static void FixupFunction (MethodInfo method, KotlinFunction metadata, KotlinCla for (var i = 0; i < java_parameters.Length; i++) { var java_p = java_parameters [i]; - var kotlin_p = metadata.ValueParameters [i]; + var kotlin_p = metadata.ValueParameters == null ? null : metadata.ValueParameters [i]; + if (kotlin_p == null || kotlin_p.Type == null || kotlin_p.Name == null) + continue; // Kotlin provides actual parameter names if (TypesMatch (java_p.Type, kotlin_p.Type, kotlinClass) && java_p.IsUnnamedParameter () && !kotlin_p.IsUnnamedParameter ()) { @@ -185,7 +194,7 @@ static void FixupFunction (MethodInfo method, KotlinFunction metadata, KotlinCla } // Handle erasure of Kotlin unsigned types - method.KotlinReturnType = GetKotlinType (method.ReturnType.TypeSignature, metadata.ReturnType.ClassName); + method.KotlinReturnType = GetKotlinType (method.ReturnType.TypeSignature, metadata.ReturnType?.ClassName); } static void FixupExtensionMethod (MethodInfo method) @@ -200,7 +209,7 @@ static void FixupExtensionMethod (MethodInfo method) } } - static void FixupProperty (MethodInfo getter, MethodInfo setter, KotlinProperty metadata) + static void FixupProperty (MethodInfo? getter, MethodInfo? setter, KotlinProperty metadata) { if (getter is null && setter is null) return; @@ -223,7 +232,7 @@ static void FixupProperty (MethodInfo getter, MethodInfo setter, KotlinProperty // Handle erasure of Kotlin unsigned types if (getter != null) - getter.KotlinReturnType = GetKotlinType (getter.ReturnType.TypeSignature, metadata.ReturnType.ClassName); + getter.KotlinReturnType = GetKotlinType (getter.ReturnType.TypeSignature, metadata.ReturnType?.ClassName); if (setter != null) { var setter_parameter = setter.GetParameters ().First (); @@ -234,42 +243,44 @@ static void FixupProperty (MethodInfo getter, MethodInfo setter, KotlinProperty } // Handle erasure of Kotlin unsigned types - setter_parameter.KotlinType = GetKotlinType (setter_parameter.Type.TypeSignature, metadata.ReturnType.ClassName); + setter_parameter.KotlinType = GetKotlinType (setter_parameter.Type.TypeSignature, metadata.ReturnType?.ClassName); } } - static void FixupField (FieldInfo field, KotlinProperty metadata) + static void FixupField (FieldInfo? field, KotlinProperty metadata) { if (field is null) return; // Handle erasure of Kotlin unsigned types - field.KotlinType = GetKotlinType (field.Descriptor, metadata.ReturnType.ClassName); + field.KotlinType = GetKotlinType (field.Descriptor, metadata.ReturnType?.ClassName); } - static MethodInfo FindJavaConstructor (KotlinClass kotlinClass, KotlinConstructor constructor, ClassFile klass) + static MethodInfo? FindJavaConstructor (KotlinClass kotlinClass, KotlinConstructor constructor, ClassFile klass) { var all_constructors = klass.Methods.Where (method => method.Name == "" || method.Name == ""); - var possible_constructors = all_constructors.Where (method => method.GetFilteredParameters ().Length == constructor.ValueParameters.Count); + var possible_constructors = all_constructors.Where (method => method.GetFilteredParameters ().Length == constructor.ValueParameters?.Count); foreach (var method in possible_constructors) { - if (ParametersMatch (kotlinClass, method, constructor.ValueParameters)) + if (ParametersMatch (kotlinClass, method, constructor.ValueParameters!)) return method; } return null; } - static MethodInfo FindJavaMethod (KotlinFile kotlinFile, KotlinFunction function, ClassFile klass) + static MethodInfo? FindJavaMethod (KotlinFile kotlinFile, KotlinFunction function, ClassFile klass) { var possible_methods = klass.Methods.Where (method => method.Name == function.JvmName && - method.GetFilteredParameters ().Length == function.ValueParameters.Count); + method.GetFilteredParameters ().Length == function.ValueParameters?.Count); foreach (var method in possible_methods) { + if (function.ReturnType == null) + continue; if (!TypesMatch (method.ReturnType, function.ReturnType, kotlinFile)) continue; - if (!ParametersMatch (kotlinFile, method, function.ValueParameters)) + if (!ParametersMatch (kotlinFile, method, function.ValueParameters!)) continue; return method; @@ -278,24 +289,26 @@ static MethodInfo FindJavaMethod (KotlinFile kotlinFile, KotlinFunction function return null; } - static FieldInfo FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) + static FieldInfo? FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) { var possible_methods = klass.Fields.Where (field => field.Name == property.Name && - TypesMatch (new TypeInfo (field.Descriptor, field.Descriptor), property.ReturnType, kotlinClass)); + property.ReturnType != null && + TypesMatch (new TypeInfo (field.Descriptor, field.Descriptor), property.ReturnType, kotlinClass)); return possible_methods.FirstOrDefault (); } - static MethodInfo FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) + static MethodInfo? FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) { 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)); + method.GetParameters ().Length == 0 && + property.ReturnType != null && + TypesMatch (method.ReturnType, property.ReturnType, kotlinClass)); return possible_methods.FirstOrDefault (); } - static MethodInfo FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) + static MethodInfo? FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) { var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"set{property.Name}", StringComparison.OrdinalIgnoreCase) == 0 && property.ReturnType != null && @@ -317,14 +330,14 @@ static bool ParametersMatch (KotlinFile kotlinClass, MethodInfo method, List (); + if (data == null) { + return null; + } return KotlinClass.FromProtobuf (data.Item1, data.Item2); } - public KotlinFile AsFileMetadata () + public KotlinFile? AsFileMetadata () { if (Kind != KotlinMetadataKind.File) return null; var data = ParseStream (); + if (data == null) { + return null; + } return KotlinFile.FromProtobuf (data.Item1, data.Item2); } - Tuple ParseStream () + Tuple? ParseStream () { + if (Data1 == null || Data2 == null) { + throw new InvalidOperationException ("Data1 is null; should not be reached."); + } + var md = KotlinBitEncoding.DecodeBytes (Data1); using (var ms = ToMemoryStream (md)) { @@ -100,7 +112,7 @@ Tuple ParseStream () static MemoryStream ToMemoryStream (byte [] bytes) => new MemoryStream (bytes); - static Version ParseVersion (Annotation annotation, string key) + static Version? ParseVersion (Annotation annotation, string key) { var value = GetValue (annotation, key); @@ -112,14 +124,21 @@ static Version ParseVersion (Annotation annotation, string key) return new Version (values [0], values [1], values [2]); } - static string GetValue (Annotation annotation, string key) + static string? GetValue (Annotation annotation, string key) { return annotation.Values.FirstOrDefault (v => v.Key == key).Value?.ToString (); } - static string[] GetValues (Annotation annotation, string key) + static string[]? GetValues (Annotation annotation, string key) { - return (annotation.Values.FirstOrDefault (v => v.Key == key).Value as AnnotationElementArray)?.Values.Cast ().Select (c => c.Value).ToArray (); + var array = annotation.Values.FirstOrDefault (v => v.Key == key).Value as AnnotationElementArray; + if (array == null || array.Values == null) { + return null; + } + var constants = array.Values.Cast (); + return constants.Select (c => c.Value!) + .Where (v => v != null) + .ToArray (); } static int ParseInteger (string value) diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs index ef91d97b0..2dd0c8639 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs @@ -1,3 +1,5 @@ +#nullable disable + // This file was generated by a tool; you should avoid making direct changes. // Consider using 'partial classes' to extend these types // Input: my.proto diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs index 7c4082f73..8b27073fa 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs @@ -8,7 +8,7 @@ namespace Xamarin.Android.Tools.Bytecode { public static class KotlinUtilities { - public static string ConvertKotlinTypeSignature (KotlinType type, KotlinFile metadata = null) + public static string ConvertKotlinTypeSignature (KotlinType? type, KotlinFile? metadata = null) { if (type is null) return string.Empty; @@ -18,9 +18,9 @@ public static string ConvertKotlinTypeSignature (KotlinType type, KotlinFile met if (string.IsNullOrWhiteSpace (class_name)) { if (metadata is KotlinClass klass) { - var tp = klass.TypeParameters.FirstOrDefault (t => t.Id == type.TypeParameter); + var tp = klass.TypeParameters?.FirstOrDefault (t => t.Id == type.TypeParameter); - if (tp?.UpperBounds.FirstOrDefault ()?.ClassName != null) + if (tp?.UpperBounds?.FirstOrDefault ()?.ClassName != null) return ConvertKotlinClassToJava (tp.UpperBounds.FirstOrDefault ()?.ClassName); } @@ -30,15 +30,15 @@ public static string ConvertKotlinTypeSignature (KotlinType type, KotlinFile met var result = ConvertKotlinClassToJava (class_name); if (result == "[") - result += ConvertKotlinTypeSignature (type.Arguments.FirstOrDefault ()?.Type); + result += ConvertKotlinTypeSignature (type.Arguments?.FirstOrDefault ()?.Type); return result; } - public static string ConvertKotlinClassToJava (string className) + public static string ConvertKotlinClassToJava (string? className) { - if (string.IsNullOrWhiteSpace (className)) - return className; + if (className == null || string.IsNullOrWhiteSpace (className)) + return string.Empty; className = className.Replace ('.', '$'); @@ -92,6 +92,16 @@ public static bool IsDefaultConstructorMarker (this MethodInfo method) parameters [parameters.Length - 1].Type.TypeSignature == "Lkotlin/jvm/internal/DefaultConstructorMarker;"; } + internal static List? ToList (this IEnumerable? self, JvmNameResolver resolver, Func creator) + where TResult: class + { + if (self == null) + return null; + return self.Select (v => creator (v, resolver)!) + .Where (v => v != null) + .ToList (); + } + public static bool IsPubliclyVisible (this ClassAccessFlags flags) => flags.HasFlag (ClassAccessFlags.Public) || flags.HasFlag (ClassAccessFlags.Protected); public static bool IsPubliclyVisible (this KotlinClassVisibility flags) => flags == KotlinClassVisibility.Public || flags == KotlinClassVisibility.Protected; @@ -104,7 +114,9 @@ public static bool IsDefaultConstructorMarker (this MethodInfo method) 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", 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", StringComparison.Ordinal) && + int.TryParse (parameter.Name.Substring (1), out var _); static Dictionary type_map = new Dictionary { { "kotlin/Int", "I" }, diff --git a/src/Xamarin.Android.Tools.Bytecode/Log.cs b/src/Xamarin.Android.Tools.Bytecode/Log.cs index bd7c70a2b..fdd77466d 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Log.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Log.cs @@ -5,7 +5,7 @@ namespace Xamarin.Android.Tools.Bytecode { public class Log { - public static Action OnLog; + public static Action? OnLog; public static void Warning (int verbosity, string format, params object[] args) { diff --git a/src/Xamarin.Android.Tools.Bytecode/Methods.cs b/src/Xamarin.Android.Tools.Bytecode/Methods.cs index c8a7eef08..ac1191ebd 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Methods.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Methods.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text; @@ -32,7 +33,7 @@ public sealed class MethodInfo { public ClassFile DeclaringType {get; private set;} public MethodAccessFlags AccessFlags {get; set;} public AttributeCollection Attributes {get; private set;} - public string KotlinReturnType {get; set;} + public string? KotlinReturnType {get; set;} public MethodInfo (ConstantPool constantPool, ClassFile declaringType, Stream stream) { @@ -67,9 +68,7 @@ public TypeInfo ReturnType { int endParams; GetParametersFromDescriptor (out endParams); endParams++; - var r = new TypeInfo { - BinaryName = Descriptor.Substring (endParams), - }; + var r = new TypeInfo (Descriptor.Substring (endParams)); r.TypeSignature = r.BinaryName; var s = GetSignature (); if (s != null) @@ -80,7 +79,7 @@ public TypeInfo ReturnType { bool IsEnumCtor => IsConstructor && DeclaringType.IsEnum; - ParameterInfo[] parameters = null; + ParameterInfo[]? parameters = null; public ParameterInfo[] GetParameters () { @@ -148,12 +147,8 @@ List GetParametersFromDescriptor (out int endParams) continue; } - var p = new ParameterInfo { - Position = c, - Name = "p" + (c++), - }; - p.Type.BinaryName = type; - p.Type.TypeSignature = type; + var p = new ParameterInfo ("p" + c, type, type, c); + c++; ps.Add (p); } endParams = index; @@ -182,12 +177,12 @@ void UpdateParametersFromLocalVariables (ParameterInfo[] parameters) } } - LocalVariableTableAttribute GetLocalVariables () + LocalVariableTableAttribute? GetLocalVariables () { var code = Attributes.Get (); if (code == null) return null; - var locals = (LocalVariableTableAttribute) code.Attributes.FirstOrDefault (a => a.Name == "LocalVariableTable"); + var locals = (LocalVariableTableAttribute?) code.Attributes.FirstOrDefault (a => a.Name == "LocalVariableTable"); return locals; } @@ -209,6 +204,7 @@ int GetDeclaredParametersCount (ParameterInfo[] parameters) if (parametersEnd == 0 || !IsConstructor || !DeclaringType.TryGetEnclosingMethodInfo (out var declaringClass, out var declaringMethodName, out var declaringMethodDescriptor) || + declaringMethodDescriptor == null || string.IsNullOrEmpty (declaringMethodDescriptor)) return parametersEnd; @@ -284,9 +280,9 @@ public List GetThrows () return throws; } - public MethodTypeSignature GetSignature () + public MethodTypeSignature? GetSignature () { - var signature = (SignatureAttribute) Attributes.SingleOrDefault (a => a.Name == "Signature"); + var signature = (SignatureAttribute?) Attributes.SingleOrDefault (a => a.Name == "Signature"); return signature != null ? new MethodTypeSignature (signature.Value) : null; @@ -294,7 +290,7 @@ public MethodTypeSignature GetSignature () void UpdateParametersFromMethodParametersAttribute (ParameterInfo[] parameters) { - var methodParams = (MethodParametersAttribute) Attributes.SingleOrDefault (a => a.Name == AttributeInfo.MethodParameters); + var methodParams = (MethodParametersAttribute?) Attributes.SingleOrDefault (a => a.Name == AttributeInfo.MethodParameters); if (methodParams == null) return; @@ -314,7 +310,7 @@ void UpdateParametersFromMethodParametersAttribute (ParameterInfo[] parameters) var p = pinfo [i + startIndex]; parameters [i].AccessFlags = p.AccessFlags; - if (p != null) { + if (p.Name != null) { parameters [i].Name = p.Name; } } @@ -331,9 +327,9 @@ public sealed class TypeInfo : IEquatable { // FieldTypeSignature, as extracted from the Signature attribute, which contains // generic type information. - public string TypeSignature; + public string? TypeSignature; - public TypeInfo (string binaryName = null, string typeSignature = null) + public TypeInfo (string binaryName, string? typeSignature = null) { BinaryName = binaryName; TypeSignature = typeSignature; @@ -344,7 +340,7 @@ public override int GetHashCode () return (BinaryName ?? "").GetHashCode () ^ (TypeSignature ?? "").GetHashCode (); } - public override bool Equals (object obj) + public override bool Equals (object? obj) { var o = obj as TypeInfo; if (o == null) @@ -352,7 +348,7 @@ public override bool Equals (object obj) return Equals (o); } - public bool Equals (TypeInfo other) + public bool Equals (TypeInfo? other) { if (other == null) return false; @@ -374,26 +370,25 @@ public sealed class ParameterInfo : IEquatable { public string Name; public int Position; - public TypeInfo Type = new TypeInfo (); - public string KotlinType; + public TypeInfo Type; + public string? KotlinType; public MethodParameterAccessFlags AccessFlags; - public ParameterInfo (string name = null, string binaryName = null, string typeSignature = null, int position = 0) + public ParameterInfo (string name, string binaryName, string? typeSignature = null, int position = 0) { Name = name; - Type.BinaryName = binaryName; - Type.TypeSignature = typeSignature; Position = position; + Type = new TypeInfo (binaryName, typeSignature); } public override int GetHashCode () { return (Name ?? "").GetHashCode () ^ Position.GetHashCode () ^ - (Type ?? new TypeInfo ()).GetHashCode (); + (Type ?? new TypeInfo ("")).GetHashCode (); } - public override bool Equals (object obj) + public override bool Equals (object? obj) { var o = obj as ParameterInfo; if (o == null) @@ -401,7 +396,7 @@ public override bool Equals (object obj) return Equals (o); } - public bool Equals (ParameterInfo other) + public bool Equals (ParameterInfo? other) { if (other == null) return false; diff --git a/src/Xamarin.Android.Tools.Bytecode/Signatures.cs b/src/Xamarin.Android.Tools.Bytecode/Signatures.cs index 8facaecdf..e514b9d2a 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Signatures.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Signatures.cs @@ -94,9 +94,7 @@ internal static void ExtractFormalTypeParameters (ICollection index++; string t; while ((t = ExtractIdentifier (signature, ref index)) != null) { - var bounds = new TypeParameterInfo { - Identifier = t, - }; + var bounds = new TypeParameterInfo (t); typeParameters.Add (bounds); AssertSignatureIndex (signature, index); @@ -131,10 +129,10 @@ internal static void ExtractFormalTypeParameters (ICollection public sealed class TypeParameterInfo { public string Identifier; - public string ClassBound; + public string? ClassBound; public List InterfaceBounds = new List (); - public TypeParameterInfo (string identifier = null, string classBound = null, string[] interfaceBounds = null) + public TypeParameterInfo (string identifier, string? classBound = null, string[]? interfaceBounds = null) { Identifier = identifier; ClassBound = classBound; diff --git a/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj b/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj index e638e5f3d..8c3562411 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj +++ b/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj @@ -1,15 +1,22 @@ - netstandard2.0 + netstandard2.0;net6.0 + 8.0 true ..\..\product.snk + INTERNAL_NULLABLE_ATTRIBUTES + enable $(TestOutputFullPath) + + + + diff --git a/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs b/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs index e32d3be6b..008137bae 100644 --- a/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs +++ b/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs @@ -11,7 +11,7 @@ namespace Xamarin.Android.Tools.Bytecode { public class XmlClassDeclarationBuilder { ClassFile classFile; - ClassSignature signature; + ClassSignature? signature; bool IsInterface { get {return (classFile.AccessFlags & ClassAccessFlags.Interface) != 0;} @@ -64,7 +64,7 @@ static string GetDeprecatedValue (AttributeCollection attributes) IEnumerable GetEnclosingMethod () { - string declaringClass, declaringMethod, declaringDescriptor; + string? declaringClass, declaringMethod, declaringDescriptor; if (!classFile.TryGetEnclosingMethodInfo (out declaringClass, out declaringMethod, out declaringDescriptor)) { yield break; } @@ -76,7 +76,7 @@ IEnumerable GetEnclosingMethod () yield return new XAttribute ("enclosing-method-signature", declaringDescriptor); } - XAttribute[] GetExtends () + XAttribute[]? GetExtends () { if (IsInterface) return null; @@ -88,7 +88,7 @@ XAttribute[] GetExtends () }; } - XAttribute GetExtendsGenericAware () + XAttribute? GetExtendsGenericAware () { if (IsInterface) return null; @@ -125,16 +125,16 @@ static string GetName (string value) return value.Replace ('$', '.'); } - static string BinaryNameToJavaClassName (string value) + static string BinaryNameToJavaClassName (string? value) { - if (string.IsNullOrEmpty (value)) + if (value == null || string.IsNullOrEmpty (value)) return string.Empty; return value.Replace ('/', '.').Replace ('$', '.'); } - string SignatureToJavaTypeName (string value) + string SignatureToJavaTypeName (string? value) { - if (string.IsNullOrEmpty (value)) + if (value == null || string.IsNullOrEmpty (value)) return string.Empty; int index = 0; var array = GetArraySuffix (value, ref index); @@ -174,9 +174,9 @@ string SignatureToJavaTypeName (string value) return value; } - static string SignatureToGenericJavaTypeName (string value) + static string SignatureToGenericJavaTypeName (string? value) { - if (string.IsNullOrEmpty (value)) + if (value == null || string.IsNullOrEmpty (value)) return string.Empty; int index = 0; var type = new StringBuilder (); @@ -240,7 +240,7 @@ static StringBuilder AppendGenericTypeNameFromSignature (StringBuilder typeBuild return typeBuilder; } - static string GetArraySuffix (string value, ref int index) + static string? GetArraySuffix (string value, ref int index) { int o = index; while (value [index] == '[') { @@ -251,7 +251,7 @@ static string GetArraySuffix (string value, ref int index) return string.Join ("", Enumerable.Repeat ("[]", index - o)); } - static string GetBuiltinName (string value, ref int index) + static string? GetBuiltinName (string value, ref int index) { switch (value [index]) { case 'B': index++; return "byte"; @@ -267,7 +267,7 @@ static string GetBuiltinName (string value, ref int index) return null; } - XAttribute GetSourceFile () + XAttribute? GetSourceFile () { var sourceFile = classFile.SourceFileName; if (sourceFile == null) @@ -275,7 +275,7 @@ XAttribute GetSourceFile () return new XAttribute ("source-file-name", sourceFile); } - XElement GetTypeParmeters (TypeParameterInfoCollection typeParameters) + XElement? GetTypeParmeters (TypeParameterInfoCollection? typeParameters) { if (typeParameters == null || typeParameters.Count == 0) return null; @@ -321,7 +321,7 @@ IEnumerable GetConstructors () .Select (c => GetMethod ("constructor", GetThisClassName (), c, null)); } - XElement GetMethod (string element, string name, MethodInfo method, string returns = null) + XElement GetMethod (string element, string name, MethodInfo method, string? returns = null) { var abstr = element == "method" ? new XAttribute ("abstract", (method.AccessFlags & MethodAccessFlags.Abstract) != 0) @@ -355,14 +355,14 @@ XElement GetMethod (string element, string name, MethodInfo method, string retur GetExceptions (method)); } - static XAttribute GetNative (MethodInfo method) + static XAttribute? GetNative (MethodInfo method) { if (method.IsConstructor) return null; return new XAttribute ("native", (method.AccessFlags & MethodAccessFlags.Native) != 0); } - static XAttribute GetSynchronized (MethodInfo method) + static XAttribute? GetSynchronized (MethodInfo method) { if (method.IsConstructor) return null; @@ -395,10 +395,10 @@ IEnumerable GetMethodParameters (MethodInfo method) if (varargArray) { Debug.Assert (p.Type.BinaryName.StartsWith ("[", StringComparison.Ordinal), "Varargs parameters MUST be arrays!"); - Debug.Assert (p.Type.TypeSignature.StartsWith ("[", StringComparison.Ordinal), + Debug.Assert (p.Type.TypeSignature != null && p.Type.TypeSignature.StartsWith ("[", StringComparison.Ordinal), "Varargs parameters MUST be arrays!"); type = type.Substring (1); - genericType = genericType.Substring (1); + genericType = genericType?.Substring (1); } genericType = SignatureToGenericJavaTypeName (genericType); if (!string.IsNullOrWhiteSpace (p.KotlinType)) @@ -410,7 +410,7 @@ IEnumerable GetMethodParameters (MethodInfo method) yield return new XElement ("parameter", new XAttribute ("name", p.Name), new XAttribute ("type", genericType), - new XAttribute ("jni-type", p.Type.TypeSignature), + new XAttribute ("jni-type", p.Type.TypeSignature ?? p.Type.BinaryName), GetNotNull (annotations, i)); } } @@ -427,7 +427,7 @@ IEnumerable GetExceptions (MethodInfo method) } } - static XAttribute GetNotNull (MethodInfo method) + static XAttribute? GetNotNull (MethodInfo method) { var annotations = method.Attributes?.OfType ().FirstOrDefault ()?.Annotations; @@ -437,7 +437,7 @@ static XAttribute GetNotNull (MethodInfo method) return null; } - static XAttribute GetNotNull (IList annotations, int parameterIndex) + static XAttribute? GetNotNull (IList? annotations, int parameterIndex) { var ann = annotations?.FirstOrDefault (a => a.ParameterIndex == parameterIndex)?.Annotations; @@ -447,7 +447,7 @@ static XAttribute GetNotNull (IList annotations, int parame return null; } - static XAttribute GetNotNull (FieldInfo field) + static XAttribute? GetNotNull (FieldInfo field) { var annotations = field.Attributes?.OfType ().FirstOrDefault ()?.Annotations; @@ -512,9 +512,9 @@ string GetGenericType (FieldInfo field) return SignatureToGenericJavaTypeName (signature); } - static XAttribute GetValue (FieldInfo field) + static XAttribute? GetValue (FieldInfo field) { - var constantValue = (ConstantValueAttribute) field.Attributes.FirstOrDefault (a => a.Name == "ConstantValue"); + var constantValue = (ConstantValueAttribute?) field.Attributes.FirstOrDefault (a => a.Name == "ConstantValue"); if (constantValue == null) return null; var value = ""; diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs index f1abac9f5..1b23e8c9f 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs @@ -23,22 +23,19 @@ public void ClassFile_WithIJavaInterface_class () FullName = "com/xamarin/IJavaInterface", Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), TypeParameters = { - new TypeParameterInfo { - Identifier = "TString", + new TypeParameterInfo ("TString") { InterfaceBounds = { "Ljava/lang/CharSequence;", "Ljava/lang/Appendable;", }, }, - new TypeParameterInfo { - Identifier = "TStringList", + new TypeParameterInfo ("TStringList") { ClassBound = "Ljava/util/ArrayList;", InterfaceBounds = { "Ljava/util/List;", }, }, - new TypeParameterInfo { - Identifier = "TReturn", + new TypeParameterInfo ("TReturn") { ClassBound = "Ljava/lang/Object;", }, }, diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs index dd9f4faaf..9981e326d 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs @@ -23,22 +23,19 @@ public void ClassFileDescription () FullName = "com/xamarin/JavaType$PSC", Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), TypeParameters = { - new TypeParameterInfo { - Identifier = "TString", + new TypeParameterInfo ("TString") { InterfaceBounds = { "Ljava/lang/CharSequence;", "Ljava/lang/Appendable;", }, }, - new TypeParameterInfo { - Identifier = "TStringList", + new TypeParameterInfo ("TStringList") { ClassBound = "Ljava/util/ArrayList;", InterfaceBounds = { "Ljava/util/List;", }, }, - new TypeParameterInfo { - Identifier = "TReturn", + new TypeParameterInfo ("TReturn") { ClassBound = "Ljava/lang/Object;", }, }, diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs index 2af262529..a2e7fc336 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs @@ -23,8 +23,7 @@ public void ClassFileDescription () FullName = "com/xamarin/JavaType$RNC$RPNC", Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), TypeParameters = { - new TypeParameterInfo { - Identifier = "E3", + new TypeParameterInfo ("E3") { ClassBound = "Ljava/lang/Object;", }, }, diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs index 87807ccbc..7a65d19d2 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs @@ -23,8 +23,7 @@ public void ClassFileDescription () FullName = "com/xamarin/JavaType$RNC", Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), TypeParameters = { - new TypeParameterInfo { - Identifier = "E2", + new TypeParameterInfo ("E2") { ClassBound = "Ljava/lang/Object;", }, }, diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs index 2c6c7a873..e91428eb0 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs @@ -25,8 +25,7 @@ public void ClassFile_WithJavaType_class () FullName = "com/xamarin/JavaType", Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), TypeParameters = { - new TypeParameterInfo { - Identifier = "E", + new TypeParameterInfo ("E") { ClassBound = "Ljava/lang/Object;", }, }, @@ -249,7 +248,7 @@ public void ClassFile_WithJavaType_class () ReturnDescriptor = "V", Deprecated = true, Parameters = { - new ParameterInfo { Name = "value", Type = new TypeInfo ("Ljava/lang/Object;", "Ljava/lang/Object;") }, + new ParameterInfo ("value", "Ljava/lang/Object;", "Ljava/lang/Object;"), }, }, new ExpectedMethodDeclaration { diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj b/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj index 406e03ede..9e43b9fa8 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj @@ -3,6 +3,7 @@ net472;net6.0 false + 8.0