diff --git a/.gitignore b/.gitignore index 06e74a2ed..fd760efe3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ xa-gendarme.html packages .vs/ *.userprefs +*.user Resource.designer.cs \ No newline at end of file diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index f9f20a83a..19c2a4394 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -695,22 +695,57 @@ protected CodeGenerator () { } - internal abstract void WriteClassHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, bool requireNew); + internal abstract void WriteClassHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, bool requireNew); - internal abstract void WriteClassHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType); + internal abstract void WriteClassHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType); - internal abstract void WriteClassInvokerHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType); - internal abstract void WriteInterfaceInvokerHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType); + internal abstract void WriteClassInvokerHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType); + internal abstract void WriteInterfaceInvokerHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType); - internal abstract void WriteConstructorIdField (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt); - internal abstract void WriteConstructorBody (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt, StringCollection call_cleanup); + internal abstract void WriteConstructorIdField (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt); + internal abstract void WriteConstructorBody (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt, StringCollection call_cleanup); - internal abstract void WriteMethodIdField (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt); - internal abstract void WriteMethodBody (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt); + internal abstract void WriteMethodIdField (Method method, TextWriter writer, string indent, CodeGenerationOptions opt); + internal abstract void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt); - internal abstract void WriteFieldIdField (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt); - internal abstract void WriteFieldGetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt); - internal abstract void WriteFieldSetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt); + internal abstract void WriteFieldIdField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt); + internal abstract void WriteFieldGetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); + internal abstract void WriteFieldSetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); + + internal virtual void WriteField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) + { + if (field.IsEnumified) + writer.WriteLine ("[global::Android.Runtime.GeneratedEnum]"); + if (field.NeedsProperty) { + string fieldType = field.Symbol.IsArray ? "IList<" + field.Symbol.ElementType + ">" : opt.GetOutputName (field.Symbol.FullName); + WriteFieldIdField (field, writer, indent, opt); + writer.WriteLine (); + writer.WriteLine ("{0}// Metadata.xml XPath field reference: path=\"{1}/field[@name='{2}']\"", indent, type.MetadataXPathReference, field.JavaName); + writer.WriteLine ("{0}[Register (\"{1}\"{2})]", indent, field.JavaName, field.AdditionalAttributeString ()); + writer.WriteLine ("{0}{1} {2}{3} {4} {{", indent, field.Visibility, field.IsStatic ? "static " : String.Empty, fieldType, field.Name); + writer.WriteLine ("{0}\tget {{", indent); + WriteFieldGetBody (field, writer, indent + "\t\t", opt, type); + writer.WriteLine ("{0}\t}}", indent); + + if (!field.IsConst) { + writer.WriteLine ("{0}\tset {{", indent); + WriteFieldSetBody (field, writer, indent + "\t\t", opt, type); + writer.WriteLine ("{0}\t}}", indent); + } + writer.WriteLine ("{0}}}", indent); + } + else { + writer.WriteLine ("{0}// Metadata.xml XPath field reference: path=\"{1}/field[@name='{2}']\"", indent, type.MetadataXPathReference, field.JavaName); + writer.WriteLine ("{0}[Register (\"{1}\"{2})]", indent, field.JavaName, field.AdditionalAttributeString ()); + if (field.IsDeprecated) + writer.WriteLine ("{0}[Obsolete (\"{1}\")]", indent, field.DeprecatedComment); + if (field.Annotation != null) + writer.WriteLine ("{0}{1}", indent, field.Annotation); + + // the Value complication is due to constant enum from negative integer value (C# compiler requires explicit parenthesis). + writer.WriteLine ("{0}{1} const {2} {3} = ({2}) {4};", indent, field.Visibility, opt.GetOutputName (field.Symbol.FullName), field.Name, field.Value.Contains ('-') && field.Symbol.FullName.Contains ('.') ? '(' + field.Value + ')' : field.Value); + } + } } } diff --git a/tools/generator/Field.cs b/tools/generator/Field.cs index 4c66716c2..31bc33c5b 100644 --- a/tools/generator/Field.cs +++ b/tools/generator/Field.cs @@ -234,45 +234,6 @@ internal ParameterList SetParameters { public string Annotation { get; internal set; } - void GenerateProperty (StreamWriter sw, string indent, CodeGenerationOptions opt, GenBase gen) - { - string type = Symbol.IsArray ? "IList<" + Symbol.ElementType + ">" : opt.GetOutputName (Symbol.FullName); - opt.CodeGenerator.WriteFieldIdField (this, sw, indent, opt); - sw.WriteLine (); - sw.WriteLine ("{0}// Metadata.xml XPath field reference: path=\"{1}/field[@name='{2}']\"", indent, gen.MetadataXPathReference, JavaName); - sw.WriteLine ("{0}[Register (\"{1}\"{2})]", indent, JavaName, this.AdditionalAttributeString ()); - sw.WriteLine ("{0}{1} {2}{3} {4} {{", indent, Visibility, IsStatic ? "static " : String.Empty, type, Name); - sw.WriteLine ("{0}\tget {{", indent); - opt.CodeGenerator.WriteFieldGetBody (this, sw, indent + "\t\t", opt); - sw.WriteLine ("{0}\t}}", indent); - - if (!IsConst) { - sw.WriteLine ("{0}\tset {{", indent); - opt.CodeGenerator.WriteFieldSetBody (this, sw, indent + "\t\t", opt); - sw.WriteLine ("{0}\t}}", indent); - } - sw.WriteLine ("{0}}}", indent); - } - - public void Generate (StreamWriter sw, string indent, CodeGenerationOptions opt, GenBase type) - { - if (IsEnumified) - sw.WriteLine ("[global::Android.Runtime.GeneratedEnum]"); - if (NeedsProperty) - GenerateProperty (sw, indent, opt, type); - else { - sw.WriteLine ("{0}// Metadata.xml XPath field reference: path=\"{1}/field[@name='{2}']\"", indent, type.MetadataXPathReference, JavaName); - sw.WriteLine ("{0}[Register (\"{1}\"{2})]", indent, JavaName, this.AdditionalAttributeString ()); - if (IsDeprecated) - sw.WriteLine ("{0}[Obsolete (\"{1}\")]", indent, DeprecatedComment); - if (Annotation != null) - sw.WriteLine ("{0}{1}", indent, Annotation); - - // the Value complication is due to constant enum from negative integer value (C# compiler requires explicit parenthesis). - sw.WriteLine ("{0}{1} const {2} {3} = ({2}) {4};", indent, Visibility, opt.GetOutputName (Symbol.FullName), Name, Value.Contains ('-') && Symbol.FullName.Contains ('.') ? '(' + Value + ')' : Value); - } - } - public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params) { symbol = SymbolTable.Lookup (TypeName, type_params); diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 5e000de2c..e9b52bb24 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -577,7 +577,7 @@ public bool GenFields (StreamWriter sw, string indent, CodeGenerationOptions opt seen.Add (f.Name); needsProperty = needsProperty || f.NeedsProperty; sw.WriteLine (); - f.Generate (sw, indent, opt, this); + opt.CodeGenerator.WriteField (f, sw, indent, opt, this); } } return needsProperty; diff --git a/tools/generator/JavaInteropCodeGenerator.cs b/tools/generator/JavaInteropCodeGenerator.cs index c515b7226..635bf56fd 100644 --- a/tools/generator/JavaInteropCodeGenerator.cs +++ b/tools/generator/JavaInteropCodeGenerator.cs @@ -19,33 +19,33 @@ static string GetInvokeType (string type) } - internal override void WriteClassHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, bool requireNew) + internal override void WriteClassHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, bool requireNew) { - sw.WriteLine ("{0}\tinternal {1} static readonly JniPeerMembers _members = new {2} (\"{3}\", typeof ({4}));", + writer.WriteLine ("{0}\tinternal {1} static readonly JniPeerMembers _members = new {2} (\"{3}\", typeof ({4}));", indent, requireNew ? "new" : " ", GetPeerMembersType (), type.RawJniName, type.Name); - sw.WriteLine ("{0}\tinternal static {1}IntPtr class_ref {{", indent, requireNew ? "new " : string.Empty); - sw.WriteLine ("{0}\t\tget {{", indent); - sw.WriteLine ("{0}\t\t\treturn _members.JniPeerType.PeerReference.Handle;", indent); - sw.WriteLine ("{0}\t\t}}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}\tinternal static {1}IntPtr class_ref {{", indent, requireNew ? "new " : string.Empty); + writer.WriteLine ("{0}\t\tget {{", indent); + writer.WriteLine ("{0}\t\t\treturn _members.JniPeerType.PeerReference.Handle;", indent); + writer.WriteLine ("{0}\t\t}}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); if (type.BaseGen != null && type.InheritsObject) { - sw.WriteLine ("{0}\tpublic override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); - sw.WriteLine ("{0}\t\tget {{ return _members; }}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}\tprotected override IntPtr ThresholdClass {{", indent); - sw.WriteLine ("{0}\t\tget {{ return _members.JniPeerType.PeerReference.Handle; }}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}\tprotected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\t\tget {{ return _members.ManagedPeerType; }}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}\tpublic override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); + writer.WriteLine ("{0}\t\tget {{ return _members; }}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}\tprotected override IntPtr ThresholdClass {{", indent); + writer.WriteLine ("{0}\t\tget {{ return _members.JniPeerType.PeerReference.Handle; }}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}\tprotected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\t\tget {{ return _members.ManagedPeerType; }}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); } } @@ -54,175 +54,175 @@ protected virtual string GetPeerMembersType () return "JniPeerMembers"; } - internal override void WriteClassHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteClassHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}new static JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));",indent, type.RawJniName, declaringType); + writer.WriteLine ("{0}new static JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));",indent, type.RawJniName, declaringType); } - internal override void WriteClassInvokerHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteClassInvokerHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", + writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", indent, type.RawJniName, declaringType); - sw.WriteLine (); - sw.WriteLine ("{0}public override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); - sw.WriteLine ("{0}\tget {{ return _members; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\tget {{ return _members.ManagedPeerType; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); + writer.WriteLine (); + writer.WriteLine ("{0}public override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); + writer.WriteLine ("{0}\tget {{ return _members; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\tget {{ return _members.ManagedPeerType; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); } - internal override void WriteInterfaceInvokerHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteInterfaceInvokerHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", + writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", indent, type.RawJniName, declaringType); - sw.WriteLine (); - sw.WriteLine ("{0}static IntPtr java_class_ref {{", indent); - sw.WriteLine ("{0}\tget {{ return _members.JniPeerType.PeerReference.Handle; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}public override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); - sw.WriteLine ("{0}\tget {{ return _members; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}protected override IntPtr ThresholdClass {{", indent); - sw.WriteLine ("{0}\tget {{ return class_ref; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\tget {{ return _members.ManagedPeerType; }}", indent, declaringType); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); + writer.WriteLine (); + writer.WriteLine ("{0}static IntPtr java_class_ref {{", indent); + writer.WriteLine ("{0}\tget {{ return _members.JniPeerType.PeerReference.Handle; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}public override global::Java.Interop.JniPeerMembers JniPeerMembers {{", indent); + writer.WriteLine ("{0}\tget {{ return _members; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}protected override IntPtr ThresholdClass {{", indent); + writer.WriteLine ("{0}\tget {{ return class_ref; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\tget {{ return _members.ManagedPeerType; }}", indent, declaringType); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); } - internal override void WriteConstructorIdField (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteConstructorIdField (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt) { // No method id_ctor field required; it's now an `id` constant in the binding. } - internal override void WriteConstructorBody (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt, System.Collections.Specialized.StringCollection call_cleanup) + internal override void WriteConstructorBody (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt, System.Collections.Specialized.StringCollection call_cleanup) { - sw.WriteLine ("{0}{1}string __id = \"{2}\";", + writer.WriteLine ("{0}{1}string __id = \"{2}\";", indent, ctor.IsNonStaticNestedType ? "" : "const ", ctor.IsNonStaticNestedType ? "(" + ctor.Parameters.JniNestedDerivedSignature + ")V" : ctor.JniSignature); - sw.WriteLine (); - sw.WriteLine ("{0}if ({1} != IntPtr.Zero)", indent, opt.ContextType.GetObjectHandleProperty ("this")); - sw.WriteLine ("{0}\treturn;", indent); - sw.WriteLine (); + writer.WriteLine (); + writer.WriteLine ("{0}if ({1} != IntPtr.Zero)", indent, opt.ContextType.GetObjectHandleProperty ("this")); + writer.WriteLine ("{0}\treturn;", indent); + writer.WriteLine (); foreach (string prep in ctor.Parameters.GetCallPrep (opt)) - sw.WriteLine ("{0}{1}", indent, prep); - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}try {{", indent); var oldindent = indent; indent += "\t"; - ctor.Parameters.WriteCallArgs (sw, indent, opt, invoker:false); - sw.WriteLine ("{0}var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (){1});", indent, ctor.Parameters.GetCallArgs (opt, invoker:false)); - sw.WriteLine ("{0}SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef);", indent); - sw.WriteLine ("{0}_members.InstanceMethods.FinishCreateInstance (__id, this{1});", indent, ctor.Parameters.GetCallArgs (opt, invoker:false)); + ctor.Parameters.WriteCallArgs (writer, indent, opt, invoker:false); + writer.WriteLine ("{0}var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (){1});", indent, ctor.Parameters.GetCallArgs (opt, invoker:false)); + writer.WriteLine ("{0}SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef);", indent); + writer.WriteLine ("{0}_members.InstanceMethods.FinishCreateInstance (__id, this{1});", indent, ctor.Parameters.GetCallArgs (opt, invoker:false)); indent = oldindent; - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); foreach (string cleanup in call_cleanup) - sw.WriteLine ("{0}\t{1}", indent, cleanup); - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}}}", indent); } - internal override void WriteMethodIdField (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteMethodIdField (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) { // No method id_ field required; it's now an `id` constant in the binding. } - internal override void WriteMethodBody (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) { - sw.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, method.JavaName, method.JniSignature); + writer.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, method.JavaName, method.JniSignature); foreach (string prep in method.Parameters.GetCallPrep (opt)) - sw.WriteLine ("{0}{1}", indent, prep); - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}try {{", indent); var oldindent = indent; indent += "\t"; - method.Parameters.WriteCallArgs (sw, indent, opt, invoker: false); + method.Parameters.WriteCallArgs (writer, indent, opt, invoker: false); var invokeType = GetInvokeType (method.RetVal.CallMethodPrefix); - sw.Write (indent); + writer.Write (indent); if (!method.IsVoid) { - sw.Write ("var __rm = "); + writer.Write ("var __rm = "); } if (method.IsStatic) { - sw.WriteLine ("_members.StaticMethods.Invoke{0}Method (__id{1});", + writer.WriteLine ("_members.StaticMethods.Invoke{0}Method (__id{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); } else if (method.IsFinal) { - sw.WriteLine ("_members.InstanceMethods.InvokeNonvirtual{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeNonvirtual{0}Method (__id, this{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); } else if (method.IsVirtual && !method.IsAbstract) { - sw.WriteLine ("_members.InstanceMethods.InvokeVirtual{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeVirtual{0}Method (__id, this{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); } else { - sw.WriteLine ("_members.InstanceMethods.InvokeAbstract{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeAbstract{0}Method (__id, this{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); } if (!method.IsVoid) { var r = invokeType == "Object" ? "__rm.Handle" : "__rm"; - sw.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, r, true)); + writer.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, r, true)); } indent = oldindent; - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); foreach (string cleanup in method.Parameters.GetCallCleanup (opt)) - sw.WriteLine ("{0}\t{1}", indent, cleanup); - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}}}", indent); } - internal override void WriteFieldIdField (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldIdField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt) { // No field id_ field required } - internal override void WriteFieldGetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldGetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { - sw.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, field.JavaName, field.Symbol.JniName); - sw.WriteLine (); + writer.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, field.JavaName, field.Symbol.JniName); + writer.WriteLine (); var invokeType = GetInvokeType (field.GetMethodPrefix); var indirect = field.IsStatic ? "StaticFields" : "InstanceFields"; var invoke = "Get{0}Value"; invoke = string.Format (invoke, invokeType); - sw.WriteLine ("{0}var __v = _members.{1}.{2} (__id{3});", + writer.WriteLine ("{0}var __v = _members.{1}.{2} (__id{3});", indent, indirect, invoke, field.IsStatic ? "" : ", this"); if (field.Symbol.IsArray) { - sw.WriteLine ("{0}return global::Android.Runtime.JavaArray<{1}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);", indent, opt.GetOutputName (field.Symbol.ElementType)); + writer.WriteLine ("{0}return global::Android.Runtime.JavaArray<{1}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);", indent, opt.GetOutputName (field.Symbol.ElementType)); } else if (field.Symbol.NativeType != field.Symbol.FullName) { - sw.WriteLine ("{0}return {1};", + writer.WriteLine ("{0}return {1};", indent, field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true)); } else { - sw.WriteLine ("{0}return __v;", indent); + writer.WriteLine ("{0}return __v;", indent); } } - internal override void WriteFieldSetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldSetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { - sw.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, field.JavaName, field.Symbol.JniName); - sw.WriteLine (); + writer.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, field.JavaName, field.Symbol.JniName); + writer.WriteLine (); var invokeType = GetInvokeType (field.GetMethodPrefix); var indirect = field.IsStatic ? "StaticFields" : "InstanceFields"; @@ -231,40 +231,40 @@ internal override void WriteFieldSetBody (Field field, StreamWriter sw, string i bool have_prep = false; if (field.Symbol.IsArray) { arg = opt.GetSafeIdentifier (SymbolTable.GetNativeName ("value")); - sw.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JavaArray<{2}>.ToLocalJniHandle (value);", indent, arg, opt.GetOutputName (field.Symbol.ElementType)); + writer.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JavaArray<{2}>.ToLocalJniHandle (value);", indent, arg, opt.GetOutputName (field.Symbol.ElementType)); } else { foreach (string prep in field.SetParameters.GetCallPrep (opt)) { have_prep = true; - sw.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}{1}", indent, prep); } arg = field.SetParameters [0].ToNative (opt); if (field.SetParameters.HasCleanup && !have_prep) { arg = opt.GetSafeIdentifier (SymbolTable.GetNativeName ("value")); - sw.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value);", indent, arg); + writer.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value);", indent, arg); } } - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}try {{", indent); - sw.WriteLine ("{0}\t_members.{1}.SetValue (__id{2}, {3});", + writer.WriteLine ("{0}\t_members.{1}.SetValue (__id{2}, {3});", indent, indirect, field.IsStatic ? "" : ", this", invokeType != "Object" ? arg : "new JniObjectReference (" + arg + ")"); - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); if (field.Symbol.IsArray) { - sw.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.DeleteLocalRef ({1});", indent, arg); + writer.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.DeleteLocalRef ({1});", indent, arg); } else { foreach (string cleanup in field.SetParameters.GetCallCleanup (opt)) - sw.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}\t{1}", indent, cleanup); if (field.SetParameters.HasCleanup && !have_prep) { - sw.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.DeleteLocalRef ({1});", indent, arg); + writer.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.DeleteLocalRef ({1});", indent, arg); } } - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}}}", indent); } } } diff --git a/tools/generator/Parameter.cs b/tools/generator/Parameter.cs index 405d459b8..9b66baa4c 100644 --- a/tools/generator/Parameter.cs +++ b/tools/generator/Parameter.cs @@ -18,7 +18,7 @@ public class Parameter { ISymbol sym; bool is_enumified; - private Parameter (string name, string type, string managedType, bool isEnumified, string rawtype = null) + internal Parameter (string name, string type, string managedType, bool isEnumified, string rawtype = null) { this.name = name; this.type = type; diff --git a/tools/generator/ParameterList.cs b/tools/generator/ParameterList.cs index 409c85857..dacd5b4c0 100644 --- a/tools/generator/ParameterList.cs +++ b/tools/generator/ParameterList.cs @@ -74,7 +74,7 @@ public string JavaCall { } } - public void WriteCallArgs (StreamWriter sw, string indent, CodeGenerationOptions opt, bool invoker) + public void WriteCallArgs (TextWriter writer, string indent, CodeGenerationOptions opt, bool invoker) { if (items.Count == 0) return; @@ -85,10 +85,10 @@ public void WriteCallArgs (StreamWriter sw, string indent, CodeGenerationOptions JValue = invoker ? JValue : "JniArgumentValue"; break; } - sw.WriteLine ("{0}{1}* __args = stackalloc {1} [{2}];", indent, JValue, items.Count); + writer.WriteLine ("{0}{1}* __args = stackalloc {1} [{2}];", indent, JValue, items.Count); for (int i = 0; i < items.Count; ++i) { var p = items [i]; - sw.WriteLine ("{0}__args [{1}] = new {2} ({3});", indent, i, JValue, p.GetCall (opt)); + writer.WriteLine ("{0}__args [{1}] = new {2} ({3});", indent, i, JValue, p.GetCall (opt)); } } diff --git a/tools/generator/Properties/AssemblyInfo.cs b/tools/generator/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0021446c8 --- /dev/null +++ b/tools/generator/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("generator-Tests")] \ No newline at end of file diff --git a/tools/generator/Tests/AccessModifiers.cs b/tools/generator/Tests/Integration-Tests/AccessModifiers.cs similarity index 100% rename from tools/generator/Tests/AccessModifiers.cs rename to tools/generator/Tests/Integration-Tests/AccessModifiers.cs diff --git a/tools/generator/Tests/Adapters.cs b/tools/generator/Tests/Integration-Tests/Adapters.cs similarity index 100% rename from tools/generator/Tests/Adapters.cs rename to tools/generator/Tests/Integration-Tests/Adapters.cs diff --git a/tools/generator/Tests/Android_Graphics_Color.cs b/tools/generator/Tests/Integration-Tests/Android_Graphics_Color.cs similarity index 100% rename from tools/generator/Tests/Android_Graphics_Color.cs rename to tools/generator/Tests/Integration-Tests/Android_Graphics_Color.cs diff --git a/tools/generator/Tests/Arrays.cs b/tools/generator/Tests/Integration-Tests/Arrays.cs similarity index 100% rename from tools/generator/Tests/Arrays.cs rename to tools/generator/Tests/Integration-Tests/Arrays.cs diff --git a/tools/generator/Tests/BaseGeneratorTest.cs b/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs similarity index 100% rename from tools/generator/Tests/BaseGeneratorTest.cs rename to tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs diff --git a/tools/generator/Tests/CSharpKeywords.cs b/tools/generator/Tests/Integration-Tests/CSharpKeywords.cs similarity index 100% rename from tools/generator/Tests/CSharpKeywords.cs rename to tools/generator/Tests/Integration-Tests/CSharpKeywords.cs diff --git a/tools/generator/Tests/Compiler.cs b/tools/generator/Tests/Integration-Tests/Compiler.cs similarity index 100% rename from tools/generator/Tests/Compiler.cs rename to tools/generator/Tests/Integration-Tests/Compiler.cs diff --git a/tools/generator/Tests/Constructors.cs b/tools/generator/Tests/Integration-Tests/Constructors.cs similarity index 100% rename from tools/generator/Tests/Constructors.cs rename to tools/generator/Tests/Integration-Tests/Constructors.cs diff --git a/tools/generator/Tests/Enumerations.cs b/tools/generator/Tests/Integration-Tests/Enumerations.cs similarity index 100% rename from tools/generator/Tests/Enumerations.cs rename to tools/generator/Tests/Integration-Tests/Enumerations.cs diff --git a/tools/generator/Tests/GenericArguments.cs b/tools/generator/Tests/Integration-Tests/GenericArguments.cs similarity index 100% rename from tools/generator/Tests/GenericArguments.cs rename to tools/generator/Tests/Integration-Tests/GenericArguments.cs diff --git a/tools/generator/Tests/InterfaceMethodsConflict.cs b/tools/generator/Tests/Integration-Tests/InterfaceMethodsConflict.cs similarity index 100% rename from tools/generator/Tests/InterfaceMethodsConflict.cs rename to tools/generator/Tests/Integration-Tests/InterfaceMethodsConflict.cs diff --git a/tools/generator/Tests/Interfaces.cs b/tools/generator/Tests/Integration-Tests/Interfaces.cs similarity index 100% rename from tools/generator/Tests/Interfaces.cs rename to tools/generator/Tests/Integration-Tests/Interfaces.cs diff --git a/tools/generator/Tests/Java_Lang_Enum.cs b/tools/generator/Tests/Integration-Tests/Java_Lang_Enum.cs similarity index 100% rename from tools/generator/Tests/Java_Lang_Enum.cs rename to tools/generator/Tests/Integration-Tests/Java_Lang_Enum.cs diff --git a/tools/generator/Tests/Java_Lang_Object.cs b/tools/generator/Tests/Integration-Tests/Java_Lang_Object.cs similarity index 100% rename from tools/generator/Tests/Java_Lang_Object.cs rename to tools/generator/Tests/Integration-Tests/Java_Lang_Object.cs diff --git a/tools/generator/Tests/Java_Util_List.cs b/tools/generator/Tests/Integration-Tests/Java_Util_List.cs similarity index 100% rename from tools/generator/Tests/Java_Util_List.cs rename to tools/generator/Tests/Integration-Tests/Java_Util_List.cs diff --git a/tools/generator/Tests/NestedTypes.cs b/tools/generator/Tests/Integration-Tests/NestedTypes.cs similarity index 100% rename from tools/generator/Tests/NestedTypes.cs rename to tools/generator/Tests/Integration-Tests/NestedTypes.cs diff --git a/tools/generator/Tests/NonStaticFields.cs b/tools/generator/Tests/Integration-Tests/NonStaticFields.cs similarity index 100% rename from tools/generator/Tests/NonStaticFields.cs rename to tools/generator/Tests/Integration-Tests/NonStaticFields.cs diff --git a/tools/generator/Tests/NormalMethods.cs b/tools/generator/Tests/Integration-Tests/NormalMethods.cs similarity index 100% rename from tools/generator/Tests/NormalMethods.cs rename to tools/generator/Tests/Integration-Tests/NormalMethods.cs diff --git a/tools/generator/Tests/NormalProperties.cs b/tools/generator/Tests/Integration-Tests/NormalProperties.cs similarity index 100% rename from tools/generator/Tests/NormalProperties.cs rename to tools/generator/Tests/Integration-Tests/NormalProperties.cs diff --git a/tools/generator/Tests/PamareterXPath.cs b/tools/generator/Tests/Integration-Tests/PamareterXPath.cs similarity index 100% rename from tools/generator/Tests/PamareterXPath.cs rename to tools/generator/Tests/Integration-Tests/PamareterXPath.cs diff --git a/tools/generator/Tests/StaticFields.cs b/tools/generator/Tests/Integration-Tests/StaticFields.cs similarity index 100% rename from tools/generator/Tests/StaticFields.cs rename to tools/generator/Tests/Integration-Tests/StaticFields.cs diff --git a/tools/generator/Tests/StaticMethods.cs b/tools/generator/Tests/Integration-Tests/StaticMethods.cs similarity index 100% rename from tools/generator/Tests/StaticMethods.cs rename to tools/generator/Tests/Integration-Tests/StaticMethods.cs diff --git a/tools/generator/Tests/StaticProperties.cs b/tools/generator/Tests/Integration-Tests/StaticProperties.cs similarity index 100% rename from tools/generator/Tests/StaticProperties.cs rename to tools/generator/Tests/Integration-Tests/StaticProperties.cs diff --git a/tools/generator/Tests/Streams.cs b/tools/generator/Tests/Integration-Tests/Streams.cs similarity index 100% rename from tools/generator/Tests/Streams.cs rename to tools/generator/Tests/Integration-Tests/Streams.cs diff --git a/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs b/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs new file mode 100644 index 000000000..ef137a3c4 --- /dev/null +++ b/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs @@ -0,0 +1,261 @@ +using MonoDroid.Generation; +using NUnit.Framework; +using System.IO; +using System.Text; + +namespace generatortests +{ + [TestFixture] + class JavaInteropCodeGeneratorTests + { + CodeGenerator generator; + StringBuilder builder; + StringWriter writer; + CodeGenerationOptions options; + + [SetUp] + public void SetUp () + { + builder = new StringBuilder (); + writer = new StringWriter (builder); + options = new CodeGenerationOptions { + CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget.JavaInterop1, + }; + generator = options.CodeGenerator; + } + + [TearDown] + public void TearDown () + { + writer.Dispose (); + } + + [Test] + public void WriteClassHandle () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + + generator.WriteClassHandle (@class, writer, string.Empty, options, false); + + Assert.AreEqual (@" internal static readonly JniPeerMembers _members = new JniPeerMembers (""com/mypackage/foo"", typeof (foo)); + internal static IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + +", builder.ToString ()); + } + + [Test] + public void WriteClassInvokerHandle () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + + generator.WriteClassInvokerHandle (@class, writer, string.Empty, options, "Com.MyPackage.Foo"); + + Assert.AreEqual (@"internal new static readonly JniPeerMembers _members = new JniPeerMembers (""com/mypackage/foo"", typeof (Com.MyPackage.Foo)); + +public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } +} + +protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } +} + +", builder.ToString ()); + } + + [Test] + public void WriteFieldIdField () + { + var field = new TestField ("java.lang.String", "bar"); + + generator.WriteFieldIdField (field, writer, string.Empty, options); + + //NOTE: not needed for JavaInteropCodeGenerator + Assert.AreEqual ("", builder.ToString ()); + } + + [Test] + public void WriteFieldGetBody () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteFieldGetBody (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"const string __id = ""bar.Ljava/lang/String;""; + +var __v = _members.InstanceFields.GetObjectValue (__id, this); +return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); +", builder.ToString ()); + } + + [Test] + public void WriteFieldSetBody () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteFieldSetBody (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"const string __id = ""bar.Ljava/lang/String;""; + +IntPtr native_value = JNIEnv.NewString (value); +try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); +} finally { + JNIEnv.DeleteLocalRef (native_value); +} +", builder.ToString ()); + } + + [Test] + public void WriteStringField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@" +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public string bar { + get { + const string __id = ""bar.Ljava/lang/String;""; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = ""bar.Ljava/lang/String;""; + + IntPtr native_value = JNIEnv.NewString (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} +", builder.ToString ()); + } + + [Test] + public void WriteIntField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@" +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public int bar { + get { + const string __id = ""bar.I""; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = ""bar.I""; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } +} +", builder.ToString ()); + } + + [Test] + public void WriteEnumifiedField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetEnumified (); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ("[global::Android.Runtime.GeneratedEnum]", builder.ToString (), "Should contain GeneratedEnumAttribute!"); + } + + [Test] + public void WriteDeprecatedField () + { + var comment = "Don't use this!"; + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetConstant ("1234").SetDeprecated (comment); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ($"[Obsolete (\"{comment}\")]", builder.ToString (), "Should contain ObsoleteAttribute!"); + } + + [Test] + public void WriteProtectedField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetVisibility ("protected"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ("protected int bar {", builder.ToString (), "Property should be protected!"); + } + + [Test] + public void WriteConstantField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant (); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@" +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public static string bar { + get { + const string __id = ""bar.Ljava/lang/String;""; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } +} +", builder.ToString ()); + } + + [Test] + public void WriteConstantFieldWithStringValue () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant ("\"hello\""); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public const string bar = (string) ""hello""; +", builder.ToString ()); + } + + [Test] + public void WriteConstantFieldWithIntValue () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetConstant ("1234"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public const int bar = (int) 1234; +", builder.ToString ()); + } + } +} diff --git a/tools/generator/Tests/Unit-Tests/SupportTypes.cs b/tools/generator/Tests/Unit-Tests/SupportTypes.cs new file mode 100644 index 000000000..14fc79521 --- /dev/null +++ b/tools/generator/Tests/Unit-Tests/SupportTypes.cs @@ -0,0 +1,140 @@ +using MonoDroid.Generation; +using System.Linq; + +namespace generatortests +{ + class TestClass : ClassGen + { + public TestClass (string baseType, string javaName) : base (new TestBaseSupport (javaName)) + { + this.BaseType = BaseType; + } + + public override bool IsAbstract => false; + + public override bool IsFinal => false; + + public override string BaseType { get; set; } + } + + class TestBaseSupport : GenBaseSupport + { + public TestBaseSupport (string javaName) + { + var split = javaName.Split ('.'); + Name = split.Last (); + FullName = javaName; + PackageName = javaName.Substring (0, javaName.Length - Name.Length - 1); + } + + public override bool IsAcw => false; + + public override bool IsDeprecated => false; + + public override string DeprecatedComment => string.Empty; + + public override bool IsGeneratable => true; + + public override bool IsGeneric => false; + + public override bool IsObfuscated => false; + + public override string FullName { get; set; } + + public override string Name { get; set; } + + public override string Namespace => PackageName; + + public override string JavaSimpleName => Name; + + public override string PackageName { get; set; } + + public override string Visibility => "public"; + + GenericParameterDefinitionList typeParameters = new GenericParameterDefinitionList (); + + public override GenericParameterDefinitionList TypeParameters => typeParameters; + } + + class TestField : Field + { + bool isFinal, isStatic, isEnumified, isDeprecated; + string type, value, deprecatedComment, visibility = "public"; + ISymbol managedSymbol; + Parameter setterParameter; + + public TestField (string type, string name) + { + this.type = type; + Name = name; + + //HACK: SymbolTable is static, hence problematic for testing + // If running a unit test first, we need to add java.lang.String. + // If an integration test was run, java.lang.String exists already. + // Down the line SymbolTable should be refactored to be non-static, so this could be done in [SetUp] + managedSymbol = SymbolTable.Lookup (type) ?? + new SimpleSymbol ("", "java.lang.String", "Ljava/lang/String;", "Java.Lang.String"); + } + + public TestField SetStatic () + { + isStatic = true; + return this; + } + + public TestField SetConstant (string value = null) + { + isFinal = + isStatic = true; + this.value = value; + return this; + } + + public TestField SetEnumified () + { + isEnumified = true; + return this; + } + + public TestField SetDeprecated (string comment = null) + { + isDeprecated = true; + deprecatedComment = comment; + return this; + } + + public TestField SetVisibility (string visibility) + { + this.visibility = visibility; + return this; + } + + public override bool IsDeprecated => isDeprecated; + + public override string DeprecatedComment => deprecatedComment; + + public override bool IsFinal => isFinal; + + public override bool IsStatic => isStatic; + + public override string JavaName => Name; + + public override bool IsEnumified => isEnumified; + + public override string TypeName => type; + + public override string Name { get; set; } + + public override string Value => value; + + public override string Visibility => visibility; + + protected override Parameter SetterParameter { + get { + if (setterParameter == null) + setterParameter = new Parameter ("value", type, managedSymbol.FullName, isEnumified); + return setterParameter; + } + } + } +} diff --git a/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs b/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs new file mode 100644 index 000000000..0936214d7 --- /dev/null +++ b/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs @@ -0,0 +1,257 @@ +using MonoDroid.Generation; +using NUnit.Framework; +using System.IO; +using System.Text; + +namespace generatortests +{ + [TestFixture] + public class XamarinAndroidCodeGeneratorTests + { + CodeGenerator generator; + StringBuilder builder; + StringWriter writer; + CodeGenerationOptions options; + + [SetUp] + public void SetUp () + { + builder = new StringBuilder (); + writer = new StringWriter (builder); + options = new CodeGenerationOptions { + CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget.XamarinAndroid, + }; + generator = options.CodeGenerator; + } + + [TearDown] + public void TearDown () + { + writer.Dispose (); + } + + [Test] + public void WriteClassHandle() + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + + generator.WriteClassHandle (@class, writer, string.Empty, options, false); + + Assert.AreEqual (@" internal static IntPtr java_class_handle; + internal static IntPtr class_ref { + get { + return JNIEnv.FindClass (""com/mypackage/foo"", ref java_class_handle); + } + } + +", builder.ToString ()); + } + + [Test] + public void WriteClassInvokerHandle () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + + generator.WriteClassInvokerHandle (@class, writer, string.Empty, options, "Com.MyPackage.Foo"); + + Assert.AreEqual (@"protected override global::System.Type ThresholdType { + get { return typeof (Com.MyPackage.Foo); } +} + +", builder.ToString ()); + } + + [Test] + public void WriteFieldIdField () + { + var field = new TestField ("java.lang.String", "bar"); + + generator.WriteFieldIdField (field, writer, string.Empty, options); + + Assert.AreEqual (@"static IntPtr bar_jfieldId; +", builder.ToString ()); + } + + [Test] + public void WriteFieldGetBody () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteFieldGetBody (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""Ljava/lang/String;""); +IntPtr __ret = JNIEnv.GetObjectField (((global::Java.Lang.Object) this).Handle, bar_jfieldId); +return JNIEnv.GetString (__ret, JniHandleOwnership.TransferLocalRef); +", builder.ToString ()); + } + + [Test] + public void WriteFieldSetBody () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteFieldSetBody (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""Ljava/lang/String;""); +IntPtr native_value = JNIEnv.NewString (value); +try { + JNIEnv.SetField (((global::Java.Lang.Object) this).Handle, bar_jfieldId, native_value); +} finally { + JNIEnv.DeleteLocalRef (native_value); +} +", builder.ToString ()); + } + + [Test] + public void WriteStringField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"static IntPtr bar_jfieldId; + +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public string bar { + get { + if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""Ljava/lang/String;""); + IntPtr __ret = JNIEnv.GetObjectField (((global::Java.Lang.Object) this).Handle, bar_jfieldId); + return JNIEnv.GetString (__ret, JniHandleOwnership.TransferLocalRef); + } + set { + if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""Ljava/lang/String;""); + IntPtr native_value = JNIEnv.NewString (value); + try { + JNIEnv.SetField (((global::Java.Lang.Object) this).Handle, bar_jfieldId, native_value); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} +", builder.ToString ()); + } + + [Test] + public void WriteIntField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"static IntPtr bar_jfieldId; + +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public int bar { + get { + if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""I""); + return JNIEnv.GetIntField (((global::Java.Lang.Object) this).Handle, bar_jfieldId); + } + set { + if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetFieldID (class_ref, ""bar"", ""I""); + try { + JNIEnv.SetField (((global::Java.Lang.Object) this).Handle, bar_jfieldId, value); + } finally { + } + } +} +", builder.ToString ()); + } + + [Test] + public void WriteEnumifiedField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetEnumified (); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ("[global::Android.Runtime.GeneratedEnum]", builder.ToString (), "Should contain GeneratedEnumAttribute!"); + } + + [Test] + public void WriteDeprecatedField () + { + var comment = "Don't use this!"; + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetConstant ("1234").SetDeprecated (comment); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ($"[Obsolete (\"{comment}\")]", builder.ToString (), "Should contain ObsoleteAttribute!"); + } + + [Test] + public void WriteProtectedField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetVisibility ("protected"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + StringAssert.Contains ("protected int bar {", builder.ToString (), "Property should be protected!"); + } + + [Test] + public void WriteConstantField () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant (); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"static IntPtr bar_jfieldId; + +// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public static string bar { + get { + if (bar_jfieldId == IntPtr.Zero) + bar_jfieldId = JNIEnv.GetStaticFieldID (class_ref, ""bar"", ""Ljava/lang/String;""); + IntPtr __ret = JNIEnv.GetStaticObjectField (class_ref, bar_jfieldId); + return JNIEnv.GetString (__ret, JniHandleOwnership.TransferLocalRef); + } +} +", builder.ToString ()); + } + + [Test] + public void WriteConstantFieldWithStringValue () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant ("\"hello\""); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public const string bar = (string) ""hello""; +", builder.ToString ()); + } + + [Test] + public void WriteConstantFieldWithIntValue () + { + var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("int", "bar").SetConstant ("1234"); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList ()), "field.Validate failed!"); + generator.WriteField (field, writer, string.Empty, options, @class); + + Assert.AreEqual (@"// Metadata.xml XPath field reference: path=""/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']"" +[Register (""bar"")] +public const int bar = (int) 1234; +", builder.ToString ()); + } + } +} diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index 4ede84fee..542a7afe3 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -42,30 +42,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -182,5 +185,8 @@ + + + - + \ No newline at end of file diff --git a/tools/generator/XamarinAndroidCodeGenerator.cs b/tools/generator/XamarinAndroidCodeGenerator.cs index 5dc77792a..ca2ff1a65 100644 --- a/tools/generator/XamarinAndroidCodeGenerator.cs +++ b/tools/generator/XamarinAndroidCodeGenerator.cs @@ -5,144 +5,144 @@ namespace MonoDroid.Generation { class XamarinAndroidCodeGenerator : CodeGenerator { - internal override void WriteClassHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, bool requireNew) + internal override void WriteClassHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, bool requireNew) { - sw.WriteLine ("{0}\tinternal static {1}IntPtr java_class_handle;", indent, requireNew ? "new " : string.Empty); - sw.WriteLine ("{0}\tinternal static {1}IntPtr class_ref {{", indent, requireNew ? "new " : string.Empty); - sw.WriteLine ("{0}\t\tget {{", indent); - sw.WriteLine ("{0}\t\t\treturn JNIEnv.FindClass (\"{1}\", ref java_class_handle);", indent, type.RawJniName); - sw.WriteLine ("{0}\t\t}}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}\tinternal static {1}IntPtr java_class_handle;", indent, requireNew ? "new " : string.Empty); + writer.WriteLine ("{0}\tinternal static {1}IntPtr class_ref {{", indent, requireNew ? "new " : string.Empty); + writer.WriteLine ("{0}\t\tget {{", indent); + writer.WriteLine ("{0}\t\t\treturn JNIEnv.FindClass (\"{1}\", ref java_class_handle);", indent, type.RawJniName); + writer.WriteLine ("{0}\t\t}}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); if (type.BaseGen != null && type.InheritsObject) { - sw.WriteLine ("{0}\tprotected override IntPtr ThresholdClass {{", indent); - sw.WriteLine ("{0}\t\tget {{ return class_ref; }}", indent); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}\tprotected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\t\tget {{ return typeof ({1}); }}", indent, type.Name); - sw.WriteLine ("{0}\t}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}\tprotected override IntPtr ThresholdClass {{", indent); + writer.WriteLine ("{0}\t\tget {{ return class_ref; }}", indent); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}\tprotected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\t\tget {{ return typeof ({1}); }}", indent, type.Name); + writer.WriteLine ("{0}\t}}", indent); + writer.WriteLine (); } } - internal override void WriteClassHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteClassHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}new static IntPtr class_ref = JNIEnv.FindClass (\"{1}\");", indent, type.RawJniName); + writer.WriteLine ("{0}new static IntPtr class_ref = JNIEnv.FindClass (\"{1}\");", indent, type.RawJniName); } - internal override void WriteClassInvokerHandle (ClassGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteClassInvokerHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\tget {{ return typeof ({1}); }}", indent, declaringType); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\tget {{ return typeof ({1}); }}", indent, declaringType); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); } - internal override void WriteInterfaceInvokerHandle (InterfaceGen type, StreamWriter sw, string indent, CodeGenerationOptions opt, string declaringType) + internal override void WriteInterfaceInvokerHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - sw.WriteLine ("{0}static IntPtr java_class_ref = JNIEnv.FindClass (\"{1}\");", indent, type.RawJniName); - sw.WriteLine (); - sw.WriteLine ("{0}protected override IntPtr ThresholdClass {{", indent); - sw.WriteLine ("{0}\tget {{ return class_ref; }}", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); - sw.WriteLine ("{0}\tget {{ return typeof ({1}); }}", indent, declaringType); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); + writer.WriteLine ("{0}static IntPtr java_class_ref = JNIEnv.FindClass (\"{1}\");", indent, type.RawJniName); + writer.WriteLine (); + writer.WriteLine ("{0}protected override IntPtr ThresholdClass {{", indent); + writer.WriteLine ("{0}\tget {{ return class_ref; }}", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}protected override global::System.Type ThresholdType {{", indent); + writer.WriteLine ("{0}\tget {{ return typeof ({1}); }}", indent, declaringType); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); } - internal override void WriteConstructorIdField (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteConstructorIdField (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt) { - sw.WriteLine ("{0}static IntPtr {1};", indent, ctor.ID); + writer.WriteLine ("{0}static IntPtr {1};", indent, ctor.ID); } - internal override void WriteConstructorBody (Ctor ctor, StreamWriter sw, string indent, CodeGenerationOptions opt, System.Collections.Specialized.StringCollection call_cleanup) + internal override void WriteConstructorBody (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt, System.Collections.Specialized.StringCollection call_cleanup) { - sw.WriteLine ("{0}if ({1} != IntPtr.Zero)", indent, opt.ContextType.GetObjectHandleProperty ("this")); - sw.WriteLine ("{0}\treturn;", indent); - sw.WriteLine (); + writer.WriteLine ("{0}if ({1} != IntPtr.Zero)", indent, opt.ContextType.GetObjectHandleProperty ("this")); + writer.WriteLine ("{0}\treturn;", indent); + writer.WriteLine (); foreach (string prep in ctor.Parameters.GetCallPrep (opt)) - sw.WriteLine ("{0}{1}", indent, prep); - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}try {{", indent); var oldindent = indent; indent += "\t"; - ctor.Parameters.WriteCallArgs (sw, indent, opt, invoker:false); - sw.WriteLine ("{0}if (((object) this).GetType () != typeof ({1})) {{", indent, ctor.Name); - sw.WriteLine ("{0}\tSetHandle (", indent); - sw.WriteLine ("{0}\t\t\tglobal::Android.Runtime.JNIEnv.StartCreateInstance (((object) this).GetType (), \"{1}\"{2}),", + ctor.Parameters.WriteCallArgs (writer, indent, opt, invoker:false); + writer.WriteLine ("{0}if (((object) this).GetType () != typeof ({1})) {{", indent, ctor.Name); + writer.WriteLine ("{0}\tSetHandle (", indent); + writer.WriteLine ("{0}\t\t\tglobal::Android.Runtime.JNIEnv.StartCreateInstance (((object) this).GetType (), \"{1}\"{2}),", indent, ctor.IsNonStaticNestedType ? "(" + ctor.Parameters.JniNestedDerivedSignature + ")V" : ctor.JniSignature, ctor.Parameters.GetCallArgs (opt, invoker:false)); - sw.WriteLine ("{0}\t\t\tJniHandleOwnership.TransferLocalRef);", indent); - sw.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.FinishCreateInstance ({1}, \"{2}\"{3});", + writer.WriteLine ("{0}\t\t\tJniHandleOwnership.TransferLocalRef);", indent); + writer.WriteLine ("{0}\tglobal::Android.Runtime.JNIEnv.FinishCreateInstance ({1}, \"{2}\"{3});", indent, opt.ContextType.GetObjectHandleProperty ("this"), ctor.IsNonStaticNestedType ? "(" + ctor.Parameters.JniNestedDerivedSignature + ")V" : ctor.JniSignature, ctor.Parameters.GetCallArgs (opt, invoker:false)); - sw.WriteLine ("{0}\treturn;", indent); - sw.WriteLine ("{0}}}", indent); - sw.WriteLine (); - sw.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, ctor.ID); - sw.WriteLine ("{0}\t{1} = JNIEnv.GetMethodID (class_ref, \"\", \"{2}\");", indent, ctor.ID, ctor.JniSignature); - sw.WriteLine ("{0}SetHandle (", indent); - sw.WriteLine ("{0}\t\tglobal::Android.Runtime.JNIEnv.StartCreateInstance (class_ref, {1}{2}),", + writer.WriteLine ("{0}\treturn;", indent); + writer.WriteLine ("{0}}}", indent); + writer.WriteLine (); + writer.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, ctor.ID); + writer.WriteLine ("{0}\t{1} = JNIEnv.GetMethodID (class_ref, \"\", \"{2}\");", indent, ctor.ID, ctor.JniSignature); + writer.WriteLine ("{0}SetHandle (", indent); + writer.WriteLine ("{0}\t\tglobal::Android.Runtime.JNIEnv.StartCreateInstance (class_ref, {1}{2}),", indent, ctor.ID, ctor.Parameters.GetCallArgs (opt, invoker:false)); - sw.WriteLine ("{0}\t\tJniHandleOwnership.TransferLocalRef);", indent); - sw.WriteLine ("{0}JNIEnv.FinishCreateInstance ({1}, class_ref, {2}{3});", + writer.WriteLine ("{0}\t\tJniHandleOwnership.TransferLocalRef);", indent); + writer.WriteLine ("{0}JNIEnv.FinishCreateInstance ({1}, class_ref, {2}{3});", indent, opt.ContextType.GetObjectHandleProperty ("this"), ctor.ID, ctor.Parameters.GetCallArgs (opt, invoker:false)); indent = oldindent; - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); foreach (string cleanup in call_cleanup) - sw.WriteLine ("{0}\t{1}", indent, cleanup); - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}}}", indent); } - internal override void WriteMethodIdField (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteMethodIdField (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) { - sw.WriteLine ("{0}static IntPtr {1};", indent, method.EscapedIdName); + writer.WriteLine ("{0}static IntPtr {1};", indent, method.EscapedIdName); } - void GenerateJNICall (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt, string call, bool declare_ret) + void GenerateJNICall (Method method, TextWriter writer, string indent, CodeGenerationOptions opt, string call, bool declare_ret) { if (method.IsVoid) - sw.WriteLine ("{0}{1};", indent, call); + writer.WriteLine ("{0}{1};", indent, call); else if (method.Parameters.HasCleanup) - sw.WriteLine ("{0}{1}__ret = {2};", indent, declare_ret ? opt.GetOutputName (method.RetVal.FullName) + " " : String.Empty, method.RetVal.FromNative (opt, call, true)); + writer.WriteLine ("{0}{1}__ret = {2};", indent, declare_ret ? opt.GetOutputName (method.RetVal.FullName) + " " : String.Empty, method.RetVal.FromNative (opt, call, true)); else - sw.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, call, true)); + writer.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, call, true)); } - internal override void WriteMethodBody (Method method, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) { - sw.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, method.EscapedIdName); - sw.WriteLine ("{0}\t{1} = JNIEnv.Get{2}MethodID (class_ref, \"{3}\", \"{4}\");", indent, method.EscapedIdName, method.IsStatic ? "Static" : String.Empty, method.JavaName, method.JniSignature); + writer.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, method.EscapedIdName); + writer.WriteLine ("{0}\t{1} = JNIEnv.Get{2}MethodID (class_ref, \"{3}\", \"{4}\");", indent, method.EscapedIdName, method.IsStatic ? "Static" : String.Empty, method.JavaName, method.JniSignature); bool use_non_virtual = method.IsVirtual && !method.IsAbstract; foreach (string prep in method.Parameters.GetCallPrep (opt)) - sw.WriteLine ("{0}{1}", indent, prep); - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}try {{", indent); var oldindent = indent; indent += "\t"; - method.Parameters.WriteCallArgs (sw, indent, opt, invoker: false); + method.Parameters.WriteCallArgs (writer, indent, opt, invoker: false); if (method.IsStatic) { - GenerateJNICall (method, sw, indent, opt, "JNIEnv.CallStatic" + method.RetVal.CallMethodPrefix + "Method (class_ref, " + method.EscapedIdName + method.Parameters.GetCallArgs (opt, invoker:false) + ")", true); + GenerateJNICall (method, writer, indent, opt, "JNIEnv.CallStatic" + method.RetVal.CallMethodPrefix + "Method (class_ref, " + method.EscapedIdName + method.Parameters.GetCallArgs (opt, invoker:false) + ")", true); } else if (use_non_virtual) { - sw.WriteLine (); + writer.WriteLine (); if (!method.IsVoid && method.Parameters.HasCleanup) - sw.WriteLine ("{0}{1} __ret;", indent, opt.GetOutputName (method.RetVal.FullName)); - sw.WriteLine ("{0}if (((object) this).GetType () == ThresholdType)", indent); - GenerateJNICall (method, sw, indent + "\t", opt, + writer.WriteLine ("{0}{1} __ret;", indent, opt.GetOutputName (method.RetVal.FullName)); + writer.WriteLine ("{0}if (((object) this).GetType () == ThresholdType)", indent); + GenerateJNICall (method, writer, indent + "\t", opt, "JNIEnv.Call" + method.RetVal.CallMethodPrefix + "Method (" + opt.ContextType.GetObjectHandleProperty ("this") + ", " + method.EscapedIdName + method.Parameters.GetCallArgs (opt, invoker:false) + ")", declare_ret: false); - sw.WriteLine ("{0}else", indent); - GenerateJNICall (method, sw, indent + "\t", opt, + writer.WriteLine ("{0}else", indent); + GenerateJNICall (method, writer, indent + "\t", opt, "JNIEnv.CallNonvirtual" + method.RetVal.CallMethodPrefix + "Method (" + opt.ContextType.GetObjectHandleProperty ("this") + ", ThresholdClass, " + @@ -152,7 +152,7 @@ internal override void WriteMethodBody (Method method, StreamWriter sw, string i } else { GenerateJNICall ( method, - sw, + writer, indent, opt, "JNIEnv.Call" + method.RetVal.CallMethodPrefix + "Method (" + @@ -163,23 +163,23 @@ internal override void WriteMethodBody (Method method, StreamWriter sw, string i } if (!method.IsVoid && method.Parameters.HasCleanup) - sw.WriteLine ("{0}return __ret;", indent); + writer.WriteLine ("{0}return __ret;", indent); indent = oldindent; - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); foreach (string cleanup in method.Parameters.GetCallCleanup (opt)) - sw.WriteLine ("{0}\t{1}", indent, cleanup); - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}}}", indent); } - internal override void WriteFieldIdField (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldIdField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt) { - sw.WriteLine ("{0}static IntPtr {1};", indent, field.ID); + writer.WriteLine ("{0}static IntPtr {1};", indent, field.ID); } - internal override void WriteFieldGetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldGetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { - sw.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, field.ID); - sw.WriteLine ("{0}\t{1} = JNIEnv.Get{2}FieldID (class_ref, \"{3}\", \"{4}\");", indent, field.ID, field.IsStatic ? "Static" : String.Empty, field.JavaName, field.Symbol.JniName); + writer.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, field.ID); + writer.WriteLine ("{0}\t{1} = JNIEnv.Get{2}FieldID (class_ref, \"{3}\", \"{4}\");", indent, field.ID, field.IsStatic ? "Static" : String.Empty, field.JavaName, field.Symbol.JniName); string call = String.Format ("JNIEnv.Get{0}{1}Field ({2}, {3})", field.IsStatic ? "Static" @@ -187,69 +187,69 @@ internal override void WriteFieldGetBody (Field field, StreamWriter sw, string i field.GetMethodPrefix, field.IsStatic ? "class_ref" - : opt.ContextType.GetObjectHandleProperty ("this"), + : type.GetObjectHandleProperty ("this"), field.ID); //var asym = Symbol as ArraySymbol; if (field.Symbol.IsArray) { - sw.WriteLine ("{0}return global::Android.Runtime.JavaArray<{1}>.FromJniHandle ({2}, JniHandleOwnership.TransferLocalRef);", indent, opt.GetOutputName (field.Symbol.ElementType), call); + writer.WriteLine ("{0}return global::Android.Runtime.JavaArray<{1}>.FromJniHandle ({2}, JniHandleOwnership.TransferLocalRef);", indent, opt.GetOutputName (field.Symbol.ElementType), call); } else if (field.Symbol.NativeType != field.Symbol.FullName) { - sw.WriteLine ("{0}{1} __ret = {2};", indent, field.Symbol.NativeType, call); - sw.WriteLine ("{0}return {1};", indent, field.Symbol.FromNative (opt, "__ret", true)); + writer.WriteLine ("{0}{1} __ret = {2};", indent, field.Symbol.NativeType, call); + writer.WriteLine ("{0}return {1};", indent, field.Symbol.FromNative (opt, "__ret", true)); } else { - sw.WriteLine ("{0}return {1};", indent, call); + writer.WriteLine ("{0}return {1};", indent, call); } } - internal override void WriteFieldSetBody (Field field, StreamWriter sw, string indent, CodeGenerationOptions opt) + internal override void WriteFieldSetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { - sw.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, field.ID); - sw.WriteLine ("{0}\t{1} = JNIEnv.Get{2}FieldID (class_ref, \"{3}\", \"{4}\");", indent, field.ID, field.IsStatic ? "Static" : String.Empty, field.JavaName, field.Symbol.JniName); + writer.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, field.ID); + writer.WriteLine ("{0}\t{1} = JNIEnv.Get{2}FieldID (class_ref, \"{3}\", \"{4}\");", indent, field.ID, field.IsStatic ? "Static" : String.Empty, field.JavaName, field.Symbol.JniName); string arg; bool have_prep = false; if (field.Symbol.IsArray) { arg = opt.GetSafeIdentifier (SymbolTable.GetNativeName ("value")); - sw.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JavaArray<{2}>.ToLocalJniHandle (value);", indent, arg, opt.GetOutputName (field.Symbol.ElementType)); + writer.WriteLine ("{0}IntPtr {1} = global::Android.Runtime.JavaArray<{2}>.ToLocalJniHandle (value);", indent, arg, opt.GetOutputName (field.Symbol.ElementType)); } else { foreach (string prep in field.SetParameters.GetCallPrep (opt)) { have_prep = true; - sw.WriteLine ("{0}{1}", indent, prep); + writer.WriteLine ("{0}{1}", indent, prep); } arg = field.SetParameters [0].ToNative (opt); if (field.SetParameters.HasCleanup && !have_prep) { arg = opt.GetSafeIdentifier (SymbolTable.GetNativeName ("value")); - sw.WriteLine ("{0}IntPtr {1} = JNIEnv.ToLocalJniHandle (value);", indent, arg); + writer.WriteLine ("{0}IntPtr {1} = JNIEnv.ToLocalJniHandle (value);", indent, arg); } } - sw.WriteLine ("{0}try {{", indent); + writer.WriteLine ("{0}try {{", indent); - sw.WriteLine ("{0}\tJNIEnv.Set{1}Field ({2}, {3}, {4});", + writer.WriteLine ("{0}\tJNIEnv.Set{1}Field ({2}, {3}, {4});", indent, field.IsStatic ? "Static" : String.Empty, field.IsStatic ? "class_ref" - : opt.ContextType.GetObjectHandleProperty ("this"), + : type.GetObjectHandleProperty ("this"), field.ID, arg); - sw.WriteLine ("{0}}} finally {{", indent); + writer.WriteLine ("{0}}} finally {{", indent); if (field.Symbol.IsArray) { - sw.WriteLine ("{0}\tJNIEnv.DeleteLocalRef ({1});", indent, arg); + writer.WriteLine ("{0}\tJNIEnv.DeleteLocalRef ({1});", indent, arg); } else { foreach (string cleanup in field.SetParameters.GetCallCleanup (opt)) - sw.WriteLine ("{0}\t{1}", indent, cleanup); + writer.WriteLine ("{0}\t{1}", indent, cleanup); if (field.SetParameters.HasCleanup && !have_prep) { - sw.WriteLine ("{0}\tJNIEnv.DeleteLocalRef ({1});", indent, arg); + writer.WriteLine ("{0}\tJNIEnv.DeleteLocalRef ({1});", indent, arg); } } - sw.WriteLine ("{0}}}", indent); + writer.WriteLine ("{0}}}", indent); } } } diff --git a/tools/generator/generator.csproj b/tools/generator/generator.csproj index 5ab46b18f..cc2eae052 100644 --- a/tools/generator/generator.csproj +++ b/tools/generator/generator.csproj @@ -1,4 +1,4 @@ - + Debug @@ -93,6 +93,7 @@ + @@ -142,4 +143,4 @@ - + \ No newline at end of file