コード例 #1
0
            private SyntaxNode ProcessNativeTypeNameAttr(AttributeSyntax nativeTypeNameAttr, out bool marshalAs)
            {
                string nativeType = nativeTypeNameAttr.ArgumentList.Arguments[0].ToString();

                nativeType = EncodeHelpers.RemoveQuotes(nativeType);

                List <AttributeSyntax> attributeNodes = new List <AttributeSyntax>();

                marshalAs = this.AddNativeTypeInfoAttribute(nativeType, attributeNodes);
                if (attributeNodes.Count == 0)
                {
                    return(null);
                }

                var ret = SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributeNodes));

                if (((AttributeListSyntax)nativeTypeNameAttr.Parent).Target is AttributeTargetSpecifierSyntax target &&
                    target.Identifier.ValueText == "return")
                {
                    ret =
                        ret.WithTarget(
                            SyntaxFactory.AttributeTargetSpecifier(
                                SyntaxFactory.Token(SyntaxKind.ReturnKeyword)));
                }

                return(ret);
            }
コード例 #2
0
            private bool GetRemapInfo(string fullName, out List <AttributeSyntax> listAttributes, string currentType, out string newType, out string newName)
            {
                if (!string.IsNullOrEmpty(fullName) && this.remaps.TryGetValue(fullName, out string remapData))
                {
                    var ret = EncodeHelpers.DecodeRemap(remapData, out listAttributes, out newType, out newName);
                    if (newType != null)
                    {
                        // Try to keep the pointers at the same level if we're replacing
                        // a uint or int. The mismatch can happen in the auto-generated
                        // enum remaps which don't know if the params/fields getting replaced
                        // are pointers or not
                        if (currentType.StartsWith("uint") || currentType.StartsWith("int") || currentType.StartsWith("short") || currentType.StartsWith("ushort"))
                        {
                            int starIndex = currentType.IndexOf('*');
                            if (starIndex != -1 && newType.IndexOf('*') == -1)
                            {
                                newType += currentType.Substring(starIndex);
                            }
                        }
                        else
                        {
                            newType = null;
                        }
                    }

                    return(ret);
                }

                listAttributes = null;
                newType        = null;
                newName        = null;

                return(false);
            }
コード例 #3
0
            private SyntaxNode ProcessGuidAttr(AttributeSyntax guidAttr)
            {
                string guidStr = guidAttr.ArgumentList.Arguments[0].ToString();

                guidStr = EncodeHelpers.RemoveQuotes(guidStr);

                Guid guid = Guid.Parse(guidStr);

                return(EncodeHelpers.ConvertGuidToAttributeList(guid));
            }
コード例 #4
0
            private bool GetRemapInfo(string fullName, out List <AttributeSyntax> listAttributes, out string newType, out string newName)
            {
                if (!string.IsNullOrEmpty(fullName) && this.remaps.TryGetValue(fullName, out string remapData))
                {
                    return(EncodeHelpers.DecodeRemap(remapData, out listAttributes, out newType, out newName));
                }

                listAttributes = null;
                newType        = null;
                newName        = null;

                return(false);
            }
コード例 #5
0
            private SyntaxNode ProcessGuidAttr(AttributeSyntax guidAttr)
            {
                string guidStr = guidAttr.ArgumentList.Arguments[0].ToString();

                guidStr = EncodeHelpers.RemoveQuotes(guidStr);

                Guid guid = Guid.Parse(guidStr);

                // Outputs in format: {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
                string formattedGuid = guid.ToString("x");

                // Get rid of leading { and trailing }}
                formattedGuid = formattedGuid.Substring(1, formattedGuid.Length - 3);
                // There's one more { we need to get rid of
                formattedGuid = formattedGuid.Replace("{", string.Empty);
                string args = $"({formattedGuid})";

                return
                    (SyntaxFactory.AttributeList(
                         SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(
                             SyntaxFactory.Attribute(
                                 SyntaxFactory.ParseName("Windows.Win32.Interop.Guid"),
                                 SyntaxFactory.ParseAttributeArgumentList(args)))));
            }
コード例 #6
0
            public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node)
            {
                string fullName = SyntaxUtils.GetFullName(node);

                this.GetRemapInfo(fullName, out var listAttributes, node.Declaration.Type.ToString(), out string newType, out string newName);

                // ClangSharp mistakenly emits string[] for WCHAR[] Foo = "Bar".
                // Change it to string
                if (newType == null && node.Declaration.Type.ToString() == "string[]")
                {
                    newType = "string";
                }

                // Turn public static readonly Guids into string constants with an attribute
                // to signal language projections to turn them into Guid constants. Guid constants
                // aren't allowed in metadata, requiring us to surface them this way
                if (node.Modifiers.ToString() == "public static readonly" && node.Declaration.Type.ToString() == "Guid")
                {
                    Guid guidVal        = Guid.Empty;
                    var  varInitializer = node.Declaration.Variables.First().Initializer;
                    if (varInitializer.Value is ObjectCreationExpressionSyntax objCreationSyntax)
                    {
                        var args = objCreationSyntax.ArgumentList.Arguments;
                        if (args.Count == 11)
                        {
                            uint   p0  = EncodeHelpers.ParseHex(args[0].ToString());
                            ushort p1  = (ushort)EncodeHelpers.ParseHex(args[1].ToString());
                            ushort p2  = (ushort)EncodeHelpers.ParseHex(args[2].ToString());
                            byte   p3  = (byte)EncodeHelpers.ParseHex(args[3].ToString());
                            byte   p4  = (byte)EncodeHelpers.ParseHex(args[4].ToString());
                            byte   p5  = (byte)EncodeHelpers.ParseHex(args[5].ToString());
                            byte   p6  = (byte)EncodeHelpers.ParseHex(args[6].ToString());
                            byte   p7  = (byte)EncodeHelpers.ParseHex(args[7].ToString());
                            byte   p8  = (byte)EncodeHelpers.ParseHex(args[8].ToString());
                            byte   p9  = (byte)EncodeHelpers.ParseHex(args[9].ToString());
                            byte   p10 = (byte)EncodeHelpers.ParseHex(args[10].ToString());

                            guidVal = new Guid(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
                        }
                        else if (objCreationSyntax.ArgumentList.Arguments.Count == 1)
                        {
                            // If this is an invalid format, remove the node
                            if (!Guid.TryParse(objCreationSyntax.ArgumentList.Arguments[0].ToString(), out guidVal))
                            {
                                return(null);
                            }
                        }
                    }

                    if (guidVal == Guid.Empty)
                    {
                        return(node);
                    }

                    node = node.RemoveNode(varInitializer, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepEndOfLine);
                    node = node.AddAttributeLists(EncodeHelpers.ConvertGuidToAttributeList(guidVal).WithLeadingTrivia(node.GetLeadingTrivia()));

                    return(node);
                }

                node = (FieldDeclarationSyntax)base.VisitFieldDeclaration(node);
                if (listAttributes != null)
                {
                    foreach (var attrNode in listAttributes)
                    {
                        var attrListNode =
                            SyntaxFactory.AttributeList(
                                SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode));
                        node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode));
                    }
                }

                var firstVar = node.Declaration.Variables.First();

                if (newName != null)
                {
                    var newVar = SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(newName));
                    node = node.ReplaceNode(firstVar, newVar);
                }

                if (newType != null)
                {
                    node = node.WithDeclaration(node.Declaration.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)));
                }

                return(node);
            }
コード例 #7
0
            private SyntaxNode CreateAttributeListForSal(AttributeListSyntax cppAttrList)
            {
                ParameterSyntax paramNode      = (ParameterSyntax)cppAttrList.Parent;
                bool            marshalAsAdded = this.nodesWithMarshalAs.Contains(paramNode);

                AttributeSyntax        cppAttr        = cppAttrList.Attributes[0];
                List <AttributeSyntax> attributesList = new List <AttributeSyntax>();

                string salText = cppAttr.ArgumentList.Arguments[0].ToString();

                salText = salText.Substring(1, salText.Length - 2);

                string marshalAsParams = null;
                bool   isIn            = false;
                bool   isOut           = false;
                bool   isOpt           = false;
                bool   isComOutPtr     = false;
                bool   isNullNullTerminated;
                bool?  pre  = null;
                bool?  post = null;

                var salAttrs = GetSalAttributes(salText);

                isNullNullTerminated = salAttrs.Any(a => a.Name == "SAL_name" && a.P1 == "_NullNull_terminated_");

                foreach (var salAttr in salAttrs)
                {
                    if (salAttr.Name == "SAL_name" && salAttr.P1.StartsWith("_COM_Outptr"))
                    {
                        isComOutPtr = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_null" && salAttr.P1 == "__maybe")
                    {
                        isOpt = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_pre")
                    {
                        pre = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_post")
                    {
                        pre  = false;
                        post = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_end")
                    {
                        pre = post = false;
                    }

                    if (salAttr.Name == "SAL_valid")
                    {
                        if (pre.HasValue && pre.Value)
                        {
                            isIn = true;
                        }
                        else if (post.HasValue && post.Value)
                        {
                            isOut = true;
                        }
                        else
                        {
                            isIn = isOut = true;
                        }

                        continue;
                    }

                    if (salAttr.Name == "SAL_name" && salAttr.P1 == "_Post_valid_")
                    {
                        isOut = true;
                        continue;
                    }

                    if (!marshalAsAdded && (salAttr.Name == "SAL_writableTo" || salAttr.Name == "SAL_readableTo") && pre.HasValue && pre.Value)
                    {
                        marshalAsParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1, isNullNullTerminated);
                        if (!string.IsNullOrEmpty(marshalAsParams))
                        {
                            marshalAsAdded = true;
                        }

                        continue;
                    }
                }

                // If we didn't add marshal as yet, try again without using pre
                if (!marshalAsAdded)
                {
                    var salAttr = salAttrs.FirstOrDefault(attr => attr.Name == "SAL_readableTo" || attr.Name == "SAL_writeableTo");
                    if (salAttr != null)
                    {
                        marshalAsParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1, isNullNullTerminated);
                        if (!string.IsNullOrEmpty(marshalAsParams))
                        {
                            marshalAsAdded = true;
                        }
                    }
                }

                if (!string.IsNullOrEmpty(marshalAsParams))
                {
                    var attrName  = SyntaxFactory.ParseName("NativeTypeInfo");
                    var args      = SyntaxFactory.ParseAttributeArgumentList(marshalAsParams.ToString());
                    var finalAttr = SyntaxFactory.Attribute(attrName, args);
                    attributesList.Add(finalAttr);
                }

                if (isIn)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("In")));
                }

                if (isComOutPtr)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("ComOutPtr")));
                }
                else if (isOut)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Out")));
                }

                if (isOpt)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Optional")));
                }

                if (attributesList.Count == 0)
                {
                    return(null);
                }

                return(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributesList)));

                string GetArrayMarshalAsFromP1(ParameterSyntax paramNode, string p1Text, bool isNullNullTerminated)
                {
                    ParameterListSyntax parameterListNode = (ParameterListSyntax)paramNode.Parent;
                    var           match        = elementCountRegex.Match(p1Text);
                    string        arraySubType = GetParameterArraySubtype(paramNode);
                    StringBuilder ret          = new StringBuilder("(UnmanagedType.LPArray");

                    if (arraySubType != null)
                    {
                        ret.Append($", ArraySubType = UnmanagedType.{arraySubType}");
                    }

                    if (isNullNullTerminated)
                    {
                        ret.Append(", IsNullNullTerminated = true");
                    }

                    if (match.Success)
                    {
                        string sizeOrParamName = match.Groups[1].Value;
                        if (int.TryParse(sizeOrParamName, out int size))
                        {
                            // Don't bother marking this as an array if it only has 1
                            if (size == 1)
                            {
                                return(string.Empty);
                            }

                            ret.Append($", SizeConst = {size}");
                        }
                        else
                        {
                            sizeOrParamName = sizeOrParamName.Replace("*", string.Empty);
                            for (int i = 0; i < parameterListNode.Parameters.Count; i++)
                            {
                                if (parameterListNode.Parameters[i].Identifier.ValueText == sizeOrParamName)
                                {
                                    ret.Append($", SizeParamIndex = {i}");
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // If it didn't match the regex and we don't see inexpressibleCount, we can't do
                        // anything but return an empty string, because we don't know how to interpret it
                        if (!p1Text.StartsWith("inexpressibleCount"))
                        {
                            ret = new StringBuilder();
                        }
                    }

                    if (ret.Length != 0)
                    {
                        ret.Append(')');
                    }

                    return(ret.ToString());

                    string GetParameterArraySubtype(ParameterSyntax paramNode)
                    {
                        foreach (var attrList in paramNode.AttributeLists)
                        {
                            foreach (var attr in attrList.Attributes)
                            {
                                if (attr.Name.ToString() == "NativeTypeName")
                                {
                                    string nativeType = attr.ArgumentList.Arguments[0].ToString();
                                    nativeType = EncodeHelpers.RemoveQuotes(nativeType);
                                    if (nativeType.StartsWith("const "))
                                    {
                                        nativeType = nativeType.Substring("const ".Length);
                                    }

                                    if (nativeType.EndsWith(" *"))
                                    {
                                        nativeType = nativeType.Substring(0, nativeType.Length - 2);
                                    }

                                    string arraySubType = ConvertTypeToMarshalAsType(nativeType, out _, out _, out _);
                                    return(arraySubType);
                                }
                            }
                        }

                        return(null);
                    }
                }

                IEnumerable <SalAttribute> GetSalAttributes(string salArgsText)
                {
                    foreach (var attr in salArgsText.Split('^'))
                    {
                        var salAttr = SalAttribute.CreateFromCppAttribute(attr);
                        if (salAttr != null)
                        {
                            yield return(salAttr);
                        }
                    }
                }
            }
コード例 #8
0
            public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node)
            {
                string fullName = GetFullName(node);

                this.GetRemapInfo(fullName, out var listAttributes, out string newType, out string newName);

                // ClangSharp mistakenly emits string[] for WCHAR[] Foo = "Bar".
                // Change it to string
                if (newType == null && node.Declaration.Type.ToString() == "string[]")
                {
                    newType = "string";
                }

                // Turn public static readonly Guids into string constants with an attribute
                // to signal language projections to turn them into Guid constants. Guid constants
                // aren't allowed in metadata, requiring us to surface them this way
                if (node.Modifiers.ToString() == "public static readonly" && node.Declaration.Type.ToString() == "Guid")
                {
                    // We're ignoring all the IID_ constants, assuming projections can get them from the interfaces
                    // directly
                    if (fullName.StartsWith("IID_"))
                    {
                        return(null);
                    }

                    string guidVal = null;
                    if (node.Declaration.Variables.First().Initializer.Value is ObjectCreationExpressionSyntax objCreationSyntax)
                    {
                        var args = objCreationSyntax.ArgumentList.Arguments;
                        if (args.Count == 11)
                        {
                            uint   p0  = EncodeHelpers.ParseHex(args[0].ToString());
                            ushort p1  = (ushort)EncodeHelpers.ParseHex(args[1].ToString());
                            ushort p2  = (ushort)EncodeHelpers.ParseHex(args[2].ToString());
                            byte   p3  = (byte)EncodeHelpers.ParseHex(args[3].ToString());
                            byte   p4  = (byte)EncodeHelpers.ParseHex(args[4].ToString());
                            byte   p5  = (byte)EncodeHelpers.ParseHex(args[5].ToString());
                            byte   p6  = (byte)EncodeHelpers.ParseHex(args[6].ToString());
                            byte   p7  = (byte)EncodeHelpers.ParseHex(args[7].ToString());
                            byte   p8  = (byte)EncodeHelpers.ParseHex(args[8].ToString());
                            byte   p9  = (byte)EncodeHelpers.ParseHex(args[9].ToString());
                            byte   p10 = (byte)EncodeHelpers.ParseHex(args[10].ToString());

                            guidVal = new Guid(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10).ToString();
                        }
                        else if (objCreationSyntax.ArgumentList.Arguments.Count == 1)
                        {
                            guidVal = EncodeHelpers.RemoveQuotes(objCreationSyntax.ArgumentList.Arguments[0].ToString());
                        }
                    }

                    if (guidVal == null)
                    {
                        return(node);
                    }

                    var variableDeclaration =
                        SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName("string")
                                                          .WithTrailingTrivia(SyntaxFactory.Space))
                        .AddVariables(
                            SyntaxFactory.VariableDeclarator(fullName)
                            .WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($"\"{guidVal}\""))));
                    var attrListSyntax   = SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Windows.Win32.Interop.GuidConst")));
                    var fieldDeclaration =
                        SyntaxFactory.FieldDeclaration(variableDeclaration)
                        .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword).WithTrailingTrivia(SyntaxFactory.Space), SyntaxFactory.Token(SyntaxKind.ConstKeyword).WithTrailingTrivia(SyntaxFactory.Space))
                        .AddAttributeLists(SyntaxFactory.AttributeList(attrListSyntax))
                        .WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed)
                        .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);

                    return(fieldDeclaration);
                }

                node = (FieldDeclarationSyntax)base.VisitFieldDeclaration(node);
                if (listAttributes != null)
                {
                    foreach (var attrNode in listAttributes)
                    {
                        var attrListNode =
                            SyntaxFactory.AttributeList(
                                SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode));
                        node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode));
                    }
                }

                var firstVar = node.Declaration.Variables.First();

                if (newName != null)
                {
                    var newVar = SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(newName));
                    node = node.ReplaceNode(firstVar, newVar);
                }

                if (newType != null)
                {
                    node = node.WithDeclaration(node.Declaration.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)));
                }

                return(node);
            }