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); }
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)); }
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))))); }
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); } } } }
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); }