From 42dfffe7ae8e35e0e1f0119920bd5bac3ad373f4 Mon Sep 17 00:00:00 2001 From: Steve Otteson Date: Thu, 25 Feb 2021 14:03:02 -0800 Subject: [PATCH] Fixes #63: Make sure all parameters have at least one of in/out attributes. Fixes #139: Better deal with params marked with __RPC__ SAL annotations --- .../ClangSharpSourceWinmdGenerator.cs | 34 +++++++++++++++++++ .../MetadataSyntaxTreeCleaner.cs | 29 ++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs b/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs index 9684d8e31..16d0ef12e 100644 --- a/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs +++ b/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs @@ -1754,6 +1754,40 @@ public Parameter(ClangSharpSourceWinmdGenerator generator, IMethodSymbol methodS parameterAttributes |= ParameterAttributes.Optional; } + // If we don't have any in/out attributes, figure out some sensible values + if (parameterAttributes == ParameterAttributes.None) + { + // https://github.com/microsoft/win32metadata/issues/63 + // * If it's a primitive or a COM pointer, it's In. + // * If it's a pointer it's In, Out, unless it's marked Const, then only In. + // * If it's a COM double pointer (e.g. IUnknown**), it's Out. + parameterAttributes |= ParameterAttributes.In; + if (paramType is IPointerTypeSymbol pointerTypeSymbol) + { + // If we're not pointing at an interface... + if (!generator.IsSymbolInterface(pointerTypeSymbol.PointedAtType)) + { + bool isConst = symbolAttrs.Any(a => a.AttributeClass.Name == "ConstAttribute"); + + // Only add Out if it's not const + if (!isConst) + { + parameterAttributes |= ParameterAttributes.Out; + } + } + + // If it's a double pointer... + if (pointerTypeSymbol.PointedAtType is IPointerTypeSymbol doublePointedAtType) + { + // Only use "Out" if it's a double COM pointer + if (generator.IsSymbolInterface(doublePointedAtType.PointedAtType)) + { + parameterAttributes = ParameterAttributes.Out; + } + } + } + } + this.Name = paramName; this.Attrs = parameterAttributes; this.Type = paramType; diff --git a/sources/ClangSharpSourceToWinmd/MetadataSyntaxTreeCleaner.cs b/sources/ClangSharpSourceToWinmd/MetadataSyntaxTreeCleaner.cs index e306ee1c7..5d8fb98cd 100644 --- a/sources/ClangSharpSourceToWinmd/MetadataSyntaxTreeCleaner.cs +++ b/sources/ClangSharpSourceToWinmd/MetadataSyntaxTreeCleaner.cs @@ -626,6 +626,35 @@ private SyntaxNode CreateAttributeListForSal(AttributeListSyntax cppAttrList) isOut = true; continue; } + else if (salAttr.P1.StartsWith("__RPC__")) + { + // TODO: Handle ecount, xcount and others that deal with counts + + string[] parts = salAttr.P1.Split('_'); + foreach (var part in parts) + { + switch (part) + { + case "in": + isIn = true; + break; + + case "out": + isOut = true; + break; + + case "inout": + isIn = isOut = true; + break; + + case "opt": + isOpt = true; + break; + } + } + + break; + } } if (salAttr.Name == "SAL_null" && salAttr.P1 == "__maybe")