private static void ParseAnnotations()

in SharpGen.Platform/CppParser.cs [320:450]


        private static void ParseAnnotations(XElement xElement, CppElement cppElement)
        {
            // Check that the xml contains the "attributes" attribute
            var attributes = xElement.AttributeValue("attributes");
            if (string.IsNullOrWhiteSpace(attributes))
                return;

            // Strip whitespaces inside annotate("...")
            var stripSpaces = new StringBuilder();
            var doubleQuoteCount = 0;
            for (var i = 0; i < attributes.Length; i++)
            {
                var addThisChar = true;
                var attributeChar = attributes[i];
                if (attributeChar == '(')
                {
                    doubleQuoteCount++;
                }
                else if (attributeChar == ')')
                {
                    doubleQuoteCount--;
                }
                else if (doubleQuoteCount > 0 && (char.IsWhiteSpace(attributeChar) | attributeChar == '"'))
                {
                    addThisChar = false;
                }
                if (addThisChar)
                    stripSpaces.Append(attributeChar);
            }
            attributes = stripSpaces.ToString();

            // Default calling convention
            var cppCallingConvention = CppCallingConvention.Unknown;

            // Default parameter attribute
            var paramAttribute = ParamAttribute.None;

            // Default Guid
            string guid = null;

            // Parse attributes
            const string gccXmlAttribute = "annotate(";
            var isPost = false;
            var hasWritable = false;

            // Clang outputs attributes in reverse order
            // TODO: Check if applies to all declarations
            foreach (var item in attributes.Split(' ').Reverse())
            {
                var newItem = item;
                if (newItem.StartsWith(gccXmlAttribute))
                    newItem = newItem.Substring(gccXmlAttribute.Length);

                if (newItem.StartsWith("SAL_pre"))
                {
                    isPost = false;
                }
                else if (newItem.StartsWith("SAL_post"))
                {
                    isPost = true;
                }
                else if (isPost && newItem.StartsWith("SAL_valid"))
                {
                    paramAttribute |= ParamAttribute.Out;
                }
                else if (newItem.StartsWith("SAL_maybenull") || (newItem.StartsWith("SAL_null") && newItem.Contains("__maybe")))
                {
                    paramAttribute |= ParamAttribute.Optional;
                }
                else if (newItem.StartsWith("SAL_readableTo") || newItem.StartsWith("SAL_writableTo"))
                {
                    if (newItem.StartsWith("SAL_writableTo"))
                    {
                        // When changing something related to in/out SAL, check resulting attributes
                        // for IInspectable::GetIids::iids (_Outptr_result_buffer_to_maybenull_)
                        // Should be Out|Buffer|Optional
                        if (!isPost) paramAttribute |= ParamAttribute.Out;
                        hasWritable = true;
                    }

                    if (!newItem.Contains("SPECSTRINGIZE(1)") && !newItem.Contains("elementCount(1)"))
                        paramAttribute |= ParamAttribute.Buffer;
                }
                else if (newItem.StartsWith("__stdcall__"))
                {
                    cppCallingConvention = CppCallingConvention.StdCall;
                }
                else if (newItem.StartsWith("__cdecl__"))
                {
                    cppCallingConvention = CppCallingConvention.CDecl;
                }
                else if (newItem.StartsWith("__thiscall__"))
                {
                    cppCallingConvention = CppCallingConvention.ThisCall;
                }
                else if (newItem.StartsWith("uuid("))
                {
                    guid = newItem.Trim(')').Substring("uuid(".Length).Trim('"', '{', '}');
                }
            }

            // If no writable, than this is an In parameter
            if (!hasWritable)
            {
                paramAttribute |= ParamAttribute.In;
            }


            // Update CppElement based on its type
            if (cppElement is CppParameter param)
            {
                // Replace in & out with inout.
                // Todo check to use in & out instead of inout
                if ((paramAttribute & ParamAttribute.In) != 0 && (paramAttribute & ParamAttribute.Out) != 0)
                {
                    paramAttribute ^= ParamAttribute.In;
                    paramAttribute ^= ParamAttribute.Out;
                    paramAttribute |= ParamAttribute.InOut;
                }

                param.Attribute = paramAttribute;
            }
            else if (cppElement is CppCallable callable && cppCallingConvention != CppCallingConvention.Unknown)
            {
                callable.CallingConvention = cppCallingConvention;
            }
            else if (cppElement is CppInterface iface && guid != null)
            {
                iface.Guid = guid;
            }
        }