Пример #1
0
        protected virtual void GenerateNamespaceMember(HierarchyNamespace ns, HierarchyElement element, string outputDirectory)
        {
            FilesystemPath path = Context.OutputPathProvider.GetPathFor(outputDirectory, element);

            if (String.IsNullOrEmpty(path?.FullPath))
            {
                Logger.Warning($"Unable to generate output for element {element.GetType ().FullName} ({element.GetManagedName (true) ?? element.FullName}) since no full path was given (at {element.GetLocation ()})");
                return;
            }

            if (path.IsDirectory)
            {
                throw new InvalidOperationException($"Namespace member must be written to a file ({ns.FullName})");
            }

            EnsureDirectory(Path.GetDirectoryName(path.FullPath));
            CheckOverwrite(path.FullPath);

            using (Stream fs = File.Open(path.FullPath, FileMode.Create)) {
                using (StreamWriter writer = new StreamWriter(fs, Context.FileEncoding)) {
                    WriteFileHeader(ns, writer);
                    OutputNamespaceMember(element, writer, path.FullPath);
                    WriteFileFooter(ns, writer);
                }
            }
        }
Пример #2
0
        // A bit clumsy but better than full-blown reflection use or an open set of Create* methods for each
        // type we support now or in the future
        protected virtual T CreateHierarchyElement <T> (HierarchyBase parent) where T : HierarchyElement
        {
            Type          type = typeof(T);
            HierarchyBase ret  = null;

            if (type == typeof(HierarchyNamespace))
            {
                ret = new HierarchyNamespace(Context, parent as Hierarchy);
            }
            else if (type == typeof(HierarchyClass))
            {
                ret = new HierarchyClass(Context, parent as HierarchyNamespace);
            }
            else if (type == typeof(HierarchyImplements))
            {
                ret = new HierarchyImplements(Context, parent as HierarchyObject);
            }
            else if (type == typeof(HierarchyMethod))
            {
                ret = new HierarchyMethod(Context, parent as HierarchyObject);
            }
            else if (type == typeof(HierarchyConstructor))
            {
                ret = new HierarchyConstructor(Context, parent as HierarchyObject);
            }
            else if (type == typeof(HierarchyException))
            {
                ret = new HierarchyException(Context, parent as HierarchyMethod);
            }
            else if (type == typeof(HierarchyTypeParameter))
            {
                ret = new HierarchyTypeParameter(Context, parent as HierarchyElement);
            }
            else if (type == typeof(HierarchyTypeParameterGenericConstraint))
            {
                ret = new HierarchyTypeParameterGenericConstraint(Context, parent as HierarchyTypeParameter);
            }
            else if (type == typeof(HierarchyMethodParameter))
            {
                ret = new HierarchyMethodParameter(Context, parent as HierarchyMethod);
            }
            else if (type == typeof(HierarchyField))
            {
                ret = new HierarchyField(Context, parent as HierarchyObject);
            }
            else if (type == typeof(HierarchyInterface))
            {
                ret = new HierarchyInterface(Context, parent as HierarchyNamespace);
            }
            else if (type == typeof(HierarchyEnum))
            {
                ret = new HierarchyEnum(Context, parent as Hierarchy);
            }
            else
            {
                throw new InvalidOperationException($"Unsupported hierarchy element type {type}");
            }

            return(ret as T);
        }
Пример #3
0
        protected virtual void Process(HierarchyNamespace parent, ApiInterface iface)
        {
            var hierarchyInterface = CreateHierarchyElementInternal <HierarchyInterface> (parent);

            hierarchyInterface.Init(iface);

            AddLocationComment(iface, hierarchyInterface);
            Helpers.ForEachNotNull(iface.ChildElements, (ApiElement e) => {
                switch (e)
                {
                case ApiField field:
                    Process(hierarchyInterface, field);
                    break;

                case ApiMethod method:
                    Process(hierarchyInterface, method);
                    break;

                case ApiImplements implements:
                    Process(hierarchyInterface, implements);
                    break;

                case ApiTypeParameter typeParameter:
                    Process(hierarchyInterface, typeParameter);
                    break;

                default:
                    Logger.Warning($"Unexpected member type for ApiInterface: '{e.GetType ().FullName}'");
                    break;
                }
            });

            parent.AddMember(hierarchyInterface);
            TypeIndex.Add(hierarchyInterface);
        }
Пример #4
0
        protected virtual void GenerateNamespace(string outputDirectoryRoot, HierarchyNamespace ns)
        {
            FilesystemPath path = Context.OutputPathProvider.GetPathFor(outputDirectoryRoot, ns);

            if (String.IsNullOrEmpty(path?.FullPath))
            {
                return;
            }

            Stream       nsFile       = null;
            StreamWriter nsFileWriter = null;

            try {
                string targetKind;
                if (path.IsDirectory)
                {
                    targetKind = "directory";
                    EnsureDirectory(path.FullPath);
                }
                else
                {
                    targetKind = "file";
                    EnsureDirectory(Path.GetDirectoryName(path.FullPath));
                    CheckOverwrite(path.FullPath);
                    nsFile       = File.Open(path.FullPath, FileMode.Create);
                    nsFileWriter = new StreamWriter(nsFile, Context.FileEncoding);
                }
                Logger.Debug($"Creating {targetKind} for namespace {ns.GetManagedName (true)}: {path.FullPath}");
                Helpers.ForEachNotNull(
                    ns.Members,
                    (HierarchyElement nsm) => {
                    if (nsFileWriter != null)
                    {
                        WriteFileHeader(ns, nsFileWriter);
                        GenerateNamespaceMember(nsm, nsFileWriter, outputDirectoryRoot);
                        WriteFileHeader(ns, nsFileWriter);
                    }
                    else
                    {
                        GenerateNamespaceMember(ns, nsm, outputDirectoryRoot);
                    }
                }
                    );
            } finally {
                if (nsFileWriter != null)
                {
                    nsFileWriter.Dispose();
                    nsFileWriter = null;
                }

                if (nsFile != null)
                {
                    nsFile.Dispose();
                    nsFile = null;
                }
            }
        }
Пример #5
0
 protected virtual void WriteFileFooter(HierarchyNamespace ns, TextWriter writer)
 {
 }
Пример #6
0
        public void Build(IList <ApiElement> rawElements)
        {
            if (rawElements == null || rawElements.Count == 0)
            {
                throw new ArgumentException("must be a non-empty collection", nameof(rawElements));
            }

            // Pass 1: build basic hierarchy (no class or interface nesting yet)
            Helpers.ForEachNotNull(rawElements, (ApiElement e) => {
                switch (e)
                {
                case ApiNameSpace ns:
                    Process(ns);
                    break;

                case ApiEnum enm:
                    Process(enm);
                    break;

                default:
                    Logger.Warning($"Unsupported top-level element type: {e.GetType ().FullName}");
                    break;
                }
            });

            HierarchyNamespace androidRuntime = namespaces?.Where(ns => String.Compare(DefaultInterfaceBaseTypeNamespace, ns?.FullName, StringComparison.OrdinalIgnoreCase) == 0).FirstOrDefault();

            if (androidRuntime == null)
            {
                Logger.Verbose("Creating Android.Runtime namespace (not found after parsing API description)");
                androidRuntime = CreateHierarchyElementInternal <HierarchyNamespace> (this);
                androidRuntime.Init();
                androidRuntime.IgnoreForCodeGeneration = true;
                androidRuntime.FullName        = DefaultInterfaceBaseTypeNamespace;
                androidRuntime.Name            = Helpers.GetBaseTypeName(androidRuntime.FullName);
                androidRuntime.ManagedName     = androidRuntime.Name;
                androidRuntime.FullManagedName = androidRuntime.FullName;
                Helpers.AddToList(androidRuntime, ref namespaces);
            }

            // IJavaObject is defined in Xamarin.Android's non-generated source and implmented by all
            // interfaces that don't derive from other interfaces
            HierarchyInterface iJavaLangObject = androidRuntime.Members?.OfType <HierarchyInterface> ().Where(iface => String.Compare(DefaultInterfaceBaseType, iface?.FullName, StringComparison.OrdinalIgnoreCase) == 0).FirstOrDefault();

            if (iJavaLangObject == null)
            {
                Logger.Verbose("Synthesizing Android.Runtime.IJavaObject interface (not found after parsing API description)");
                iJavaLangObject = CreateHierarchyElementInternal <HierarchyInterface> (androidRuntime);
                iJavaLangObject.Init();
                iJavaLangObject.FullName = DefaultInterfaceBaseType;
                iJavaLangObject.Name     = Helpers.GetBaseTypeName(iJavaLangObject.FullName);
                iJavaLangObject.IgnoreForCodeGeneration = true;
                iJavaLangObject.InvokerNotNeeded        = true;
                iJavaLangObject.UseGlobal = true;
                TypeIndex.Add(iJavaLangObject);
            }

            // Pass 2: nest classes, interfaces
            NestNamespaces();

            // Pass 3: generate managed names
            Helpers.ForEachNotNull(namespaces, (HierarchyNamespace ns) => GenerateManagedNames(ns));

            // TODO: fix generation of full managed names for enums
            Helpers.ForEachNotNull(enums, (HierarchyEnum enm) => GenerateManagedNames(enm));

            // Pass 4: nest enums (they need managed names)
            NestEnums();

            // Pass 5: generate and inject synthetic elements
            SynthesizeElements();

            // Pass 6: resolve base types since we have everything in place now
            ResolveBaseTypes();

            // Pass 7: sort class members
        }