Пример #1
0
        public static void AddInterfaceListenerEventsAndProperties(TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt)
        {
            if (!iface.IsValid)
            {
                return;
            }

            foreach (var method in iface.Methods)
            {
                var nameSpec   = iface.Methods.Count > 1 ? method.EventName ?? method.AdjustedName : string.Empty;
                var nameUnique = string.IsNullOrEmpty(nameSpec) ? name : nameSpec;

                if (nameUnique.StartsWith("On"))
                {
                    nameUnique = nameUnique.Substring(2);
                }

                if (target.ContainsName(nameUnique))
                {
                    nameUnique += "Event";
                }

                AddInterfaceListenerEventOrProperty(tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt);
            }
        }
Пример #2
0
        public static void AddInterfaceListenerEventOrProperty(TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt)
        {
            if (method.EventName == string.Empty)
            {
                return;
            }

            var nameSpec           = iface.Methods.Count > 1 ? method.AdjustedName : string.Empty;
            var idx                = iface.FullName.LastIndexOf(".");
            var start              = iface.Name.StartsWith("IOn") ? 3 : 1;
            var full_delegate_name = iface.FullName.Substring(0, idx + 1) + iface.Name.Substring(start, iface.Name.Length - start - 8) + nameSpec;

            if (method.IsSimpleEventHandler)
            {
                full_delegate_name = "EventHandler";
            }
            else if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty)
            {
                full_delegate_name = "EventHandler<" + iface.FullName.Substring(0, idx + 1) + iface.GetArgsName(method) + ">";
            }
            else
            {
                full_delegate_name += "Handler";
            }

            if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty)
            {
                if (opt.GetSafeIdentifier(name) != name)
                {
                    Report.LogCodedWarning(0, Report.WarningInvalidEventName2, method, iface.FullName, name);
                    return;
                }
                else
                {
                    var mt = target.Methods.Where(method => string.Compare(method.Name, connector_fmt, StringComparison.OrdinalIgnoreCase) == 0 && method.IsListenerConnector).FirstOrDefault();
                    var hasHandlerArgument = mt != null && mt.IsListenerConnector && mt.Parameters.Count == 2 && mt.Parameters [1].Type == "Android.OS.Handler";

                    tw.Events.Add(new InterfaceListenerEvent(iface, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt));
                }
            }
            else
            {
                if (opt.GetSafeIdentifier(name) != name)
                {
                    Report.LogCodedWarning(0, Report.WarningInvalidEventPropertyName, method, iface.FullName, name);
                    return;
                }

                tw.Properties.Add(new InterfaceListenerPropertyImplementor(iface, name, opt));
                tw.Properties.Add(new InterfaceListenerProperty(iface, name, nameSpec, method.AdjustedName, full_delegate_name, opt));
            }
        }
Пример #3
0
        public static void Run(CodeGeneratorOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            string assemblyQN              = options.AssemblyQualifiedName;
            string api_level               = options.ApiLevel;
            int    product_version         = options.ProductVersion;
            bool   preserve_enums          = options.PreserveEnums;
            string csdir                   = options.ManagedCallableWrapperSourceOutputDirectory ?? "cs";
            string javadir                 = "java";
            string enumdir                 = options.EnumOutputDirectory ?? "enum";
            string enum_metadata           = options.EnumMetadataOutputFile ?? "enummetadata";
            var    references              = options.AssemblyReferences;
            string enum_fields_map         = options.EnumFieldsMapFile;
            string enum_flags              = options.EnumFlagsFile;
            string enum_methods_map        = options.EnumMethodsMapFile;
            var    fixups                  = options.FixupFiles;
            string api_versions_xml        = options.ApiVersionsXmlFile;
            var    annotations_zips        = options.AnnotationsZipFiles;
            string filename                = options.ApiDescriptionFile;
            string mapping_file            = options.MappingReportFile;
            bool   only_xml_adjuster       = options.OnlyRunApiXmlAdjuster;
            string api_xml_adjuster_output = options.ApiXmlAdjusterOutput;
            var    apiSource               = "";
            var    opt = new CodeGenerationOptions()
            {
                CodeGenerationTarget = options.CodeGenerationTarget,
                UseGlobal            = options.GlobalTypeNames,
                IgnoreNonPublicType  = true,
                UseShortFileNames    = options.UseShortFileNames,
                ProductVersion       = options.ProductVersion
            };

            // Load reference libraries

            var resolver = new DirectoryAssemblyResolver(Console.WriteLine, loadDebugSymbols: false);

            foreach (var lib in options.LibraryPaths)
            {
                resolver.SearchDirectories.Add(lib);
            }
            foreach (var reference in references)
            {
                resolver.SearchDirectories.Add(Path.GetDirectoryName(reference));
            }
            foreach (var reference in references)
            {
                try {
                    Report.Verbose(0, "resolving assembly {0}.", reference);
                    var assembly = resolver.Load(reference);
                    foreach (var md in assembly.Modules)
                    {
                        foreach (var td in md.Types)
                        {
                            // FIXME: at some stage we want to import generic types.
                            // For now generator fails to load generic types that have conflicting type e.g.
                            // AdapterView`1 and AdapterView cannot co-exist.
                            // It is mostly because generator primarily targets jar (no real generics land).
                            if (td.HasGenericParameters &&
                                md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`'))) != null)
                            {
                                continue;
                            }
                            ProcessReferencedType(td, opt);
                        }
                    }
                } catch (Exception ex) {
                    Report.Warning(0, Report.WarningCodeGenerator + 0, ex, "failed to parse assembly {0}: {1}", reference, ex.Message);
                }
            }

            // For class-parse API description, transform it to jar2xml style.
            string apiXmlFile = filename;

            string apiSourceAttr = null;

            using (var xr = XmlReader.Create(filename)) {
                xr.MoveToContent();
                apiSourceAttr = xr.GetAttribute("api-source");
            }
            if (apiSourceAttr == "class-parse")
            {
                apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                new Adjuster().Process(filename, SymbolTable.AllRegisteredSymbols().OfType <GenBase> ().ToArray(), apiXmlFile);
            }
            if (only_xml_adjuster)
            {
                return;
            }

            // load XML API definition with fixups.

            Dictionary <string, EnumMappings.EnumDescription> enums = null;

            EnumMappings enummap = null;

            if (enum_fields_map != null || enum_methods_map != null)
            {
                enummap = new EnumMappings(enumdir, enum_metadata, api_level, preserve_enums);
                enums   = enummap.Process(enum_fields_map, enum_flags, enum_methods_map);
                fixups.Add(enum_metadata);
            }

            Parser         p    = new Parser();
            List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version);

            if (gens == null)
            {
                return;
            }
            apiSource = p.ApiSource;
            opt.Gens  = gens;

            // disable interface default methods here, especially before validation.
            foreach (var gen in gens)
            {
                gen.StripNonBindables();
            }

            Validate(gens, opt);

            if (api_versions_xml != null)
            {
                ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml, api_level);
            }

            foreach (GenBase gen in gens)
            {
                gen.FillProperties();
            }

            foreach (var gen in gens)
            {
                gen.UpdateEnums(opt);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupMethodOverrides();
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupExplicitImplementation();
            }

            GenerateAnnotationAttributes(gens, annotations_zips);

            //SymbolTable.Dump ();

            GenerationInfo gen_info = new GenerationInfo(csdir, javadir, assemblyQN);

            opt.AssemblyName = gen_info.Assembly;

            if (mapping_file != null)
            {
                GenerateMappingReportFile(gens, mapping_file);
            }

            new NamespaceMapping(gens).Generate(opt, gen_info);

            foreach (IGeneratable gen in gens)
            {
                if (gen.IsGeneratable)
                {
                    gen.Generate(opt, gen_info);
                }
            }

            ClassGen.GenerateTypeRegistrations(opt, gen_info);
            ClassGen.GenerateEnumList(gen_info);

            // Create the .cs files for the enums
            var enumFiles = enums == null
                                ? null
                                : enummap.WriteEnumerations(enumdir, enums, FlattenNestedTypes(gens).ToArray(), opt.UseShortFileNames);

            gen_info.GenerateLibraryProjectFile(options, enumFiles);
        }
Пример #4
0
        public static void AddInterfaceListenerEventsAndProperties(TypeWriter tw, InterfaceGen iface, ClassGen target, CodeGenerationOptions opt)
        {
            var methods      = target.Methods.Concat(target.Properties.Where(p => p.Setter != null).Select(p => p.Setter));
            var props        = new HashSet <string> ();
            var refs         = new HashSet <string> ();
            var eventMethods = methods.Where(m => m.IsListenerConnector && m.EventName != string.Empty && m.ListenerType == iface).OrderBy(m => m.Parameters.Count).GroupBy(m => m.Name).Select(g => g.First()).Distinct();

            foreach (var method in eventMethods)
            {
                var name = method.CalculateEventName(target.ContainsName);

                if (string.IsNullOrEmpty(name))
                {
                    Report.LogCodedWarning(0, Report.WarningEmptyEventName, method, iface.FullName, method.Name);
                    continue;
                }

                if (opt.GetSafeIdentifier(name) != name)
                {
                    Report.LogCodedWarning(0, Report.WarningInvalidEventName, method, iface.FullName, method.Name);
                    continue;
                }

                var prop = target.Properties.FirstOrDefault(p => p.Setter == method);

                if (prop != null)
                {
                    var setter = "__Set" + prop.Name;
                    props.Add(prop.Name);
                    refs.Add(setter);

                    AddInterfaceListenerEventsAndProperties(tw, iface, target, name, setter,
                                                            string.Format("__v => {0} = __v", prop.Name),
                                                            string.Format("__v => {0} = null", prop.Name), opt);
                }
                else
                {
                    refs.Add(method.Name);
                    string rm = null;
                    string remove;

                    if (method.Name.StartsWith("Set"))
                    {
                        remove = string.Format("__v => {0} (null)", method.Name);
                    }
                    else if (method.Name.StartsWith("Add") &&
                             (rm = "Remove" + method.Name.Substring("Add".Length)) != null &&
                             methods.Where(m => m.Name == rm).Any())
                    {
                        remove = string.Format("__v => {0} (__v)", rm);
                    }
                    else
                    {
                        remove = string.Format("__v => {{throw new NotSupportedException (\"Cannot unregister from {0}.{1}\");}}",
                                               iface.FullName, method.Name);
                    }

                    AddInterfaceListenerEventsAndProperties(tw, iface, target, name, method.Name,
                                                            method.Name,
                                                            remove, opt);
                }
            }

            foreach (var r in refs)
            {
                tw.Fields.Add(new WeakImplementorField(r, opt));
            }

            tw.Methods.Add(new CreateImplementorMethod(iface, opt));
        }
Пример #5
0
        static void Run(CodeGeneratorOptions options, DirectoryAssemblyResolver resolver)
        {
            string assemblyQN              = options.AssemblyQualifiedName;
            string api_level               = options.ApiLevel;
            int    product_version         = options.ProductVersion;
            bool   preserve_enums          = options.PreserveEnums;
            string csdir                   = options.ManagedCallableWrapperSourceOutputDirectory ?? "cs";
            string javadir                 = "java";
            string enumdir                 = options.EnumOutputDirectory ?? "enum";
            string enum_metadata           = options.EnumMetadataOutputFile ?? "enummetadata";
            var    references              = options.AssemblyReferences;
            string enum_fields_map         = options.EnumFieldsMapFile;
            string enum_flags              = options.EnumFlagsFile;
            string enum_methods_map        = options.EnumMethodsMapFile;
            var    fixups                  = options.FixupFiles;
            var    annotations_zips        = options.AnnotationsZipFiles;
            string filename                = options.ApiDescriptionFile;
            string mapping_file            = options.MappingReportFile;
            bool   only_xml_adjuster       = options.OnlyRunApiXmlAdjuster;
            string api_xml_adjuster_output = options.ApiXmlAdjusterOutput;
            var    apiSource               = "";
            var    opt = new CodeGenerationOptions()
            {
                CodeGenerationTarget           = options.CodeGenerationTarget,
                UseGlobal                      = options.GlobalTypeNames,
                IgnoreNonPublicType            = true,
                UseShortFileNames              = options.UseShortFileNames,
                ProductVersion                 = options.ProductVersion,
                SupportInterfaceConstants      = options.SupportInterfaceConstants,
                SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods,
                SupportNestedInterfaceTypes    = options.SupportNestedInterfaceTypes,
            };
            var resolverCache = new TypeDefinitionCache();

            // Load reference libraries

            foreach (var lib in options.LibraryPaths)
            {
                resolver.SearchDirectories.Add(lib);
            }
            foreach (var reference in references)
            {
                resolver.SearchDirectories.Add(Path.GetDirectoryName(reference));
            }

            // Figure out if this is class-parse
            string apiXmlFile    = filename;
            string apiSourceAttr = null;

            using (var xr = XmlReader.Create(filename)) {
                xr.MoveToContent();
                apiSourceAttr = xr.GetAttribute("api-source");
            }

            // We don't use shallow referenced types with class-parse because the Adjuster process
            // enumerates every ctor/method/property/field to build its model, so we will need
            // every type to be fully populated.
            opt.UseShallowReferencedTypes = apiSourceAttr != "class-parse";

            foreach (var reference in references.Distinct())
            {
                try {
                    Report.Verbose(0, "resolving assembly {0}.", reference);
                    var assembly = resolver.Load(reference);
                    foreach (var md in assembly.Modules)
                    {
                        foreach (var td in md.Types)
                        {
                            // FIXME: at some stage we want to import generic types.
                            // For now generator fails to load generic types that have conflicting type e.g.
                            // AdapterView`1 and AdapterView cannot co-exist.
                            // It is mostly because generator primarily targets jar (no real generics land).
                            var nonGenericOverload = td.HasGenericParameters
                                                                ? md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`')))
                                                                : null;
                            if (BindSameType(td, nonGenericOverload, resolverCache))
                            {
                                continue;
                            }
                            ProcessReferencedType(td, opt);
                        }
                    }
                } catch (Exception ex) {
                    Report.Warning(0, Report.WarningCodeGenerator + 0, ex, "failed to parse assembly {0}: {1}", reference, ex.Message);
                }
            }

            // For class-parse API description, transform it to jar2xml style.
            if (apiSourceAttr == "class-parse")
            {
                apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                new Adjuster().Process(filename, opt, opt.SymbolTable.AllRegisteredSymbols(opt).OfType <GenBase> ().ToArray(), apiXmlFile, Report.Verbosity ?? 0);
            }
            if (only_xml_adjuster)
            {
                return;
            }

            // load XML API definition with fixups.

            Dictionary <string, EnumMappings.EnumDescription> enums = null;

            EnumMappings enummap = null;

            if (enum_fields_map != null || enum_methods_map != null)
            {
                enummap = new EnumMappings(enumdir, enum_metadata, api_level, preserve_enums);
                enums   = enummap.Process(enum_fields_map, enum_flags, enum_methods_map);
                fixups.Add(enum_metadata);
            }

            Parser         p    = new Parser(opt);
            List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version);

            if (gens == null)
            {
                return;
            }
            apiSource = p.ApiSource;

            // disable interface default methods here, especially before validation.
            gens = gens.Where(g => !g.IsObfuscated && g.Visibility != "private").ToList();
            foreach (var gen in gens)
            {
                gen.StripNonBindables(opt);
                if (gen.IsGeneratable)
                {
                    AddTypeToTable(opt, gen);
                }
            }

            // Apply fixups
            KotlinFixups.Fixup(gens);

            Validate(gens, opt, new CodeGeneratorContext());

            foreach (var api_versions_xml in options.ApiVersionsXmlFiles)
            {
                ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml);
            }

            foreach (GenBase gen in gens)
            {
                gen.FillProperties();
            }

            var cache = new AncestorDescendantCache(gens);

            foreach (var gen in gens)
            {
                gen.UpdateEnums(opt, cache);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupMethodOverrides(opt);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupExplicitImplementation();
            }

            SealedProtectedFixups.Fixup(gens);

            GenerateAnnotationAttributes(gens, annotations_zips);

            //SymbolTable.Dump ();

            GenerationInfo gen_info = new GenerationInfo(csdir, javadir, assemblyQN);

            opt.AssemblyName = gen_info.Assembly;

            if (mapping_file != null)
            {
                GenerateMappingReportFile(gens, mapping_file);
            }

            new NamespaceMapping(gens).Generate(opt, gen_info);

            foreach (IGeneratable gen in gens)
            {
                if (gen.IsGeneratable)
                {
                    gen.Generate(opt, gen_info);
                }
            }


            ClassGen.GenerateTypeRegistrations(opt, gen_info);
            ClassGen.GenerateEnumList(gen_info);

            // Create the .cs files for the enums
            var enumFiles = enums == null
                                ? null
                                : enummap.WriteEnumerations(enumdir, enums, FlattenNestedTypes(gens).ToArray(), opt.UseShortFileNames);

            gen_info.GenerateLibraryProjectFile(options, enumFiles);
        }
Пример #6
0
        public BoundClass(ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo generationInfo)
        {
            context.ContextTypes.Push(klass);
            context.ContextGeneratedMethods = new List <Method> ();

            generationInfo.TypeRegistrations.Add(new KeyValuePair <string, string> (klass.RawJniName, klass.AssemblyQualifiedName));

            var is_enum = klass.base_symbol != null && klass.base_symbol.FullName == "Java.Lang.Enum";

            if (is_enum)
            {
                generationInfo.Enums.Add(klass.RawJniName.Replace('/', '.') + ":" + klass.Namespace + ":" + klass.JavaSimpleName);
            }

            this.opt = opt;

            Name = klass.Name;

            SetVisibility(klass.Visibility);
            IsShadow   = klass.NeedsNew;
            IsAbstract = klass.IsAbstract;
            IsSealed   = klass.IsFinal;
            IsPartial  = true;

            UsePriorityOrder = true;

            AddImplementedInterfaces(klass);

            Comments.Add($"// Metadata.xml XPath class reference: path=\"{klass.MetadataXPathReference}\"");

            if (klass.IsDeprecated)
            {
                Attributes.Add(new ObsoleteAttr(klass.DeprecatedComment)
                {
                    WriteAttributeSuffix = true
                });
            }

            Attributes.Add(new RegisterAttr(klass.RawJniName, null, null, true, klass.AdditionalAttributeString())
            {
                UseGlobal = true, UseShortForm = true
            });

            if (klass.TypeParameters != null && klass.TypeParameters.Any())
            {
                Attributes.Add(new CustomAttr(klass.TypeParameters.ToGeneratedAttributeString()));
            }

            // Figure out our base class
            string obj_type = null;

            if (klass.base_symbol != null)
            {
                obj_type = klass.base_symbol is GenericSymbol gs &&
                           gs.IsConcrete ? gs.GetGenericType(null) : opt.GetOutputName(klass.base_symbol.FullName);
            }

            if (klass.InheritsObject && obj_type != null)
            {
                Inherits = obj_type;
            }

            // Handle fields
            var seen = new HashSet <string> ();

            SourceWriterExtensions.AddFields(this, klass, klass.Fields, seen, opt, context);

            var ic = new InterfaceConstsClass(klass, seen, opt, context);

            if (ic.ShouldGenerate)
            {
                NestedTypes.Add(ic);
            }

            // Sibling classes
            if (!klass.AssemblyQualifiedName.Contains('/'))
            {
                foreach (InterfaceExtensionInfo nestedIface in klass.GetNestedInterfaceTypes())
                {
                    if (nestedIface.Type.Methods.Any(m => m.CanHaveStringOverload) || nestedIface.Type.Methods.Any(m => m.Asyncify))
                    {
                        sibling_types.Add(new InterfaceExtensionsClass(nestedIface.Type, nestedIface.DeclaringType, opt));
                    }
                }
            }

            if (klass.IsAbstract)
            {
                sibling_types.Add(new ClassInvokerClass(klass, opt));
            }

            AddNestedTypes(klass, opt, context, generationInfo);
            AddBindingInfrastructure(klass);
            AddConstructors(klass, opt, context);
            AddProperties(klass, opt);
            AddMethods(klass, opt, context);
            AddAbstractMembers(klass, opt, context);
            AddExplicitGenericInterfaceMembers(klass, opt);
            AddCharSequenceEnumerator(klass);

            context.ContextGeneratedMethods.Clear();
            context.ContextTypes.Pop();
        }
Пример #7
0
        public ClassInvokerClass(ClassGen klass, CodeGenerationOptions opt)
        {
            Name = $"{klass.Name}Invoker";

            IsInternal       = true;
            IsPartial        = true;
            UsePriorityOrder = true;

            Inherits = klass.Name;

            foreach (var igen in klass.GetAllDerivedInterfaces().Where(i => i.IsGeneric))
            {
                Implements.Add(opt.GetOutputName(igen.FullName));
            }

            if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1)
            {
                Attributes.Add(new JniTypeSignatureAttr(klass.RawJniName, false));
            }
            else
            {
                Attributes.Add(new RegisterAttr(klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString())
                {
                    UseGlobal = true
                });
            }

            SourceWriterExtensions.AddSupportedOSPlatform(Attributes, klass, opt);

            ConstructorWriter ctor = opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1
                                ? new ConstructorWriter {
                Name       = Name,
                IsPublic   = true,
                BaseCall   = "base (ref reference, options)",
                Parameters =
                {
                    new MethodParameterWriter("reference", new TypeReferenceWriter("ref JniObjectReference")),
                    new MethodParameterWriter("options",   new TypeReferenceWriter("JniObjectReferenceOptions")),
                },
            }
                                : new ConstructorWriter {
                Name       = Name,
                IsPublic   = true,
                BaseCall   = "base (handle, transfer)",
                Parameters =
                {
                    new MethodParameterWriter("handle",   TypeReferenceWriter.IntPtr),
                    new MethodParameterWriter("transfer", new TypeReferenceWriter("JniHandleOwnership")),
                },
            }
            ;

            Constructors.Add(ctor);

            // ClassInvokerHandle
            Fields.Add(new PeerMembersField(opt, klass.RawJniName, $"{klass.Name}Invoker", false));
            Properties.Add(new JniPeerMembersGetter());
            if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1)
            {
                Properties.Add(new ThresholdTypeGetter());
            }

            AddMemberInvokers(klass, opt, new HashSet <string> ());
        }