diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs index e39403f9f..69fb3964f 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs @@ -71,6 +71,9 @@ protected List ParseApiDefinition (string xml) foreach (var gen in gens) options.SymbolTable.AddType (gen); + foreach (var gen in gens) + gen.FixupAccessModifiers (options); + foreach (var gen in gens) gen.Validate (options, new GenericParameterDefinitionList (), generator.Context); diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs index df1359fff..6e8e68c08 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs @@ -827,6 +827,55 @@ public void DontWarnIfNestedTypeNameMatchesNamespace () Assert.False (sb.ToString ().Contains ("warning BG8403")); } + + [Test] + public void AvoidNREOnInvalidBaseMethod () + { + // We copy methods from the package-private base class to the public class, however + // the copied method is not valid because it doesn't understand the generic argument + // type. The method is remove from the public class, but we need to ensure the + // base class method still exists and IsValid. + var xml = @" + + + + + + + + + + + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + var public_class = gens.Single (g => g.Name == "Behavior"); + var base_class = gens.Single (g => g.Name == "ViewOffsetBehavior"); + + // Method got removed + Assert.AreEqual (0, public_class.Methods.Count); + + // Method still exists and is valid + Assert.AreEqual (1, base_class.Methods.Count); + Assert.AreEqual (true, base_class.Methods [0].IsValid); + } + static string StripRegisterAttributes (string str) { // It is hard to test if the [Obsolete] is on the setter/etc due to the [Register], so remove all [Register]s diff --git a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs index a19d6b224..762a41a21 100644 --- a/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs +++ b/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs @@ -40,7 +40,7 @@ public unsafe void PublicMethod () } } - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassB']/method[@name='packageMethodB' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodB' and count(parameter)=0]" [global::Java.Interop.JniMethodSignature ("packageMethodB", "()V")] public unsafe void PackageMethodB () { @@ -51,7 +51,7 @@ public unsafe void PackageMethodB () } } - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassA']/method[@name='packageMethodA' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodA' and count(parameter)=0]" [global::Java.Interop.JniMethodSignature ("packageMethodA", "()V")] public unsafe void PackageMethodA () { diff --git a/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs b/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs index 8a4ebcfff..f1258d3ec 100644 --- a/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs +++ b/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs @@ -57,7 +57,7 @@ public unsafe void PublicMethod () } } - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassB']/method[@name='packageMethodB' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodB' and count(parameter)=0]" [Register ("packageMethodB", "()V", "")] public unsafe void PackageMethodB () { @@ -68,7 +68,7 @@ public unsafe void PackageMethodB () } } - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassA']/method[@name='packageMethodA' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodA' and count(parameter)=0]" [Register ("packageMethodA", "()V", "")] public unsafe void PackageMethodA () { diff --git a/tests/generator-Tests/expected/AccessModifiers/Xamarin.Test.PublicFinalClass.cs b/tests/generator-Tests/expected/AccessModifiers/Xamarin.Test.PublicFinalClass.cs index 80687ecde..9e89768d5 100644 --- a/tests/generator-Tests/expected/AccessModifiers/Xamarin.Test.PublicFinalClass.cs +++ b/tests/generator-Tests/expected/AccessModifiers/Xamarin.Test.PublicFinalClass.cs @@ -49,7 +49,7 @@ public unsafe void PublicMethod () } static IntPtr id_packageMethodB; - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassB']/method[@name='packageMethodB' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodB' and count(parameter)=0]" [Register ("packageMethodB", "()V", "")] public unsafe void PackageMethodB () { @@ -62,7 +62,7 @@ public unsafe void PackageMethodB () } static IntPtr id_packageMethodA; - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PackageClassA']/method[@name='packageMethodA' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodA' and count(parameter)=0]" [Register ("packageMethodA", "()V", "")] public unsafe void PackageMethodA () { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs index d274cb311..6d0e96705 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs @@ -63,7 +63,7 @@ public override void FixupAccessModifiers (CodeGenerationOptions opt) foreach (var baseMethod in baseClass.Methods) { var method = Methods.FirstOrDefault (m => m.Matches (baseMethod)); if (method == null) - Methods.Add (baseMethod); + Methods.Add (baseMethod.Clone (this)); } BaseType = baseClass.BaseType; } else { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs index e4a39e9ea..353afedcc 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs @@ -49,6 +49,11 @@ public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList validated = is_valid = true; return true; } + + public GenericParameterDefinition Clone () + { + return new GenericParameterDefinition (Name, ConstraintExpressions); + } } public class GenericParameterDefinitionList : List diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs index bae3faf1f..9d194db41 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs @@ -107,6 +107,57 @@ internal string CalculateEventName (Func checkNameDuplicate) public bool CanHaveStringOverload => IsReturnCharSequence || Parameters.HasCharSequence; + public Method Clone (GenBase declaringType) + { + var clone = new Method (declaringType); + + // MethodBase + clone.Annotation = Annotation; + clone.ApiAvailableSince = ApiAvailableSince; + clone.AssemblyName = AssemblyName; + clone.Deprecated = Deprecated; + clone.DeprecatedSince = DeprecatedSince; + clone.IsAcw = IsAcw; + clone.Name = Name; + clone.Visibility = Visibility; + clone.LineNumber = LineNumber; + clone.LinePosition = LinePosition; + clone.SourceFile = SourceFile; + clone.JavadocInfo = JavadocInfo; + + if (GenericArguments != null) + foreach (var ga in GenericArguments) + clone.GenericArguments.Add (ga.Clone ()); + + foreach (var p in Parameters) + clone.Parameters.Add (p.Clone ()); + + // Method + clone.ArgsType = ArgsType; + clone.CustomAttributes = CustomAttributes; + clone.EventName = EventName; + clone.GenerateAsyncWrapper = GenerateAsyncWrapper; + clone.GenerateDispatchingSetter = GenerateDispatchingSetter; + clone.IsAbstract = IsAbstract; + clone.IsFinal = IsFinal; + clone.IsInterfaceDefaultMethod = IsInterfaceDefaultMethod; + clone.OverriddenInterfaceMethod = OverriddenInterfaceMethod; + clone.IsReturnEnumified = IsReturnEnumified; + clone.IsStatic = IsStatic; + clone.IsVirtual = IsVirtual; + clone.JavaName = JavaName; + clone.ManagedOverride = ManagedOverride; + clone.ManagedReturn = ManagedReturn; + clone.PropertyNameOverride = PropertyNameOverride; + clone.Return = Return; + clone.ReturnNotNull = ReturnNotNull; + clone.RetVal = RetVal.Clone (clone); + clone.SourceApiLevel = SourceApiLevel; + clone.ExplicitInterface = ExplicitInterface; + + return clone; + } + public string ConnectorName => $"Get{Name}{IDSignature}Handler"; public string EscapedCallbackName => IdentifierValidator.CreateValidIdentifier ($"cb_{JavaName}{IDSignature}", true); diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs index 4a7c6e35c..1b99758cb 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs @@ -32,7 +32,12 @@ internal Parameter (string name, string type, string managedType, bool isEnumifi this.is_enumified = isEnumified; NotNull = notNull; } - + + public Parameter Clone () + { + return new Parameter (name, type, managed_type, is_enumified, rawtype, NotNull); + } + public string GetCall (CodeGenerationOptions opt) { var rgm = sym as IRequireGenericMarshal; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs index 1fe885d78..85ee1718c 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs @@ -28,6 +28,11 @@ public ReturnValue (Method owner, string java_type, string managed_type, bool is public string CallMethodPrefix => TypeNameUtilities.GetCallPrefix (sym); + public ReturnValue Clone (Method owner) + { + return new ReturnValue (owner, java_type, managed_type, is_enumified, NotNull); + } + public string DefaultValue { get { return sym.DefaultValue; } }