From 3721a3a42886f691efe3300bdc234fa5bdae4ffc Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 1 Nov 2019 23:35:46 -0400 Subject: [PATCH 1/4] Failing tests for unsafe methods and fields --- .../Field_modifiers.cs | 25 ++++++++++++++++++- .../Method_modifiers.cs | 22 ++++++++++++++++ .../PublicApiGeneratorTests.csproj | 3 ++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/PublicApiGeneratorTests/Field_modifiers.cs b/src/PublicApiGeneratorTests/Field_modifiers.cs index b150836..489a88d 100644 --- a/src/PublicApiGeneratorTests/Field_modifiers.cs +++ b/src/PublicApiGeneratorTests/Field_modifiers.cs @@ -56,7 +56,7 @@ public void Include_const_fields() // Have to include the ctor - I can't figure out how to hide it // when values are initialized AssertPublicApi( -@"namespace PublicApiGeneratorTests.Examples + @"namespace PublicApiGeneratorTests.Examples { public class ClassWithConstFields { @@ -64,6 +64,23 @@ public class ClassWithConstFields public const int ConstPublicField = 42; public ClassWithConstFields() { } } +}"); + } + + [Fact] + public void Include_unsafe_fields() + { + // Have to include the ctor - I can't figure out how to hide it + // when values are initialized + AssertPublicApi( + @"namespace PublicApiGeneratorTests.Examples +{ + public class ClassWithUnsafeFields + { + protected unsafe System.Void* UnsafeProtectedField; + public unsafe System.Void* UnsafePublicField; + public ClassWithUnsafeFields() { } + } }"); } } @@ -94,6 +111,12 @@ public class ClassWithConstFields public const int ConstPublicField = 42; protected const string ConstProtectedField = "hello world"; } + + public class ClassWithUnsafeFields + { + public unsafe void* UnsafePublicField; + protected unsafe void* UnsafeProtectedField; + } } // ReSharper restore UnusedMember.Global // ReSharper restore ClassNeverInstantiated.Global diff --git a/src/PublicApiGeneratorTests/Method_modifiers.cs b/src/PublicApiGeneratorTests/Method_modifiers.cs index 15b6ff2..09045c2 100644 --- a/src/PublicApiGeneratorTests/Method_modifiers.cs +++ b/src/PublicApiGeneratorTests/Method_modifiers.cs @@ -86,6 +86,20 @@ public class ClassWithMethodHiding : PublicApiGeneratorTests.Examples.ClassWithS public ClassWithMethodHiding() { } public new void Method() { } } +}"); + } + + [Fact] + public void Should_output_unsafe_modifier() + { + AssertPublicApi( + @"namespace PublicApiGeneratorTests.Examples +{ + public class ClassWithUnsafeMethod + { + public ClassWithUnsafeMethod() { } + public unsafe System.Void* DoSomething() { } + } }"); } } @@ -146,6 +160,14 @@ public override string ToString() return base.ToString(); } } + + public class ClassWithUnsafeMethod + { + public unsafe void* DoSomething() + { + return null; + } + } } // ReSharper restore ClassWithVirtualMembersNeverInherited.Global // ReSharper restore RedundantOverridenMember diff --git a/src/PublicApiGeneratorTests/PublicApiGeneratorTests.csproj b/src/PublicApiGeneratorTests/PublicApiGeneratorTests.csproj index b088829..e78d61a 100644 --- a/src/PublicApiGeneratorTests/PublicApiGeneratorTests.csproj +++ b/src/PublicApiGeneratorTests/PublicApiGeneratorTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2 @@ -9,6 +9,7 @@ IDE0060 Remove unused parameter 'name' if it is not part of a shipped public API IDE1006 Naming rule violation: These words must begin with upper case characters --> + true From f960f9db3dd8150fb2a8a895833ce89fefb7b285 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 1 Nov 2019 23:38:06 -0400 Subject: [PATCH 2/4] Add unsafe modifier when necessary --- src/PublicApiGenerator/ApiGenerator.cs | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/PublicApiGenerator/ApiGenerator.cs b/src/PublicApiGenerator/ApiGenerator.cs index b425fc6..71856ea 100644 --- a/src/PublicApiGenerator/ApiGenerator.cs +++ b/src/PublicApiGenerator/ApiGenerator.cs @@ -626,6 +626,9 @@ static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, Meth var returnType = member.ReturnType.CreateCodeTypeReference(member.MethodReturnType); + if (IsUnsafeSignatureType(member.ReturnType) || member.Parameters.Any(p => IsUnsafeSignatureType(p.ParameterType))) + returnType = MakeUnsafe(returnType); + var method = new CodeMemberMethod { Name = memberName, @@ -640,6 +643,22 @@ static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, Meth typeDeclaration.Members.Add(method); } + static bool IsUnsafeSignatureType(TypeReference typeReference) + { + while (true) + { + if (typeReference.IsPointer) return true; + + if (typeReference.IsArray || typeReference.IsByReference) + { + typeReference = typeReference.GetElementType(); + continue; + } + + return false; + } + } + static bool IsExtensionMethod(ICustomAttributeProvider method) { return method.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); @@ -889,6 +908,9 @@ static void AddFieldToTypeDeclaration(CodeTypeDeclaration typeDeclaration, Field var codeTypeReference = memberInfo.FieldType.CreateCodeTypeReference(memberInfo); if (memberInfo.IsInitOnly) codeTypeReference = MakeReadonly(codeTypeReference); + if (IsUnsafeSignatureType(memberInfo.FieldType)) + codeTypeReference = MakeUnsafe(codeTypeReference); + var field = new CodeMemberField(codeTypeReference, memberInfo.Name) { Attributes = attributes, @@ -906,6 +928,11 @@ static CodeTypeReference MakeReadonly(CodeTypeReference typeReference) return ModifyCodeTypeReference(typeReference, "readonly"); } + static CodeTypeReference MakeUnsafe(CodeTypeReference typeReference) + { + return ModifyCodeTypeReference(typeReference, "unsafe"); + } + static CodeTypeReference ModifyCodeTypeReference(CodeTypeReference typeReference, string modifier) { using (var provider = new CSharpCodeProvider()) From dbc7eaa71b2148b7af6928ccbf1508f209595228 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Sat, 2 Nov 2019 21:30:15 +0300 Subject: [PATCH 3/4] System.Void -> void --- src/PublicApiGenerator/CSharpTypeKeyword.cs | 2 ++ src/PublicApiGenerator/CodeTypeReferenceBuilder.cs | 5 +++++ src/PublicApiGeneratorTests/Field_modifiers.cs | 4 ++-- src/PublicApiGeneratorTests/Method_modifiers.cs | 6 +++--- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/PublicApiGenerator/CSharpTypeKeyword.cs b/src/PublicApiGenerator/CSharpTypeKeyword.cs index 8172f73..45f4095 100644 --- a/src/PublicApiGenerator/CSharpTypeKeyword.cs +++ b/src/PublicApiGenerator/CSharpTypeKeyword.cs @@ -34,6 +34,8 @@ public static string Get(string typeName) return "string"; case "System.Boolean": return "bool"; + case "System.Void": + return "void"; default: return typeName; } diff --git a/src/PublicApiGenerator/CodeTypeReferenceBuilder.cs b/src/PublicApiGenerator/CodeTypeReferenceBuilder.cs index aada8e9..54e3e0e 100644 --- a/src/PublicApiGenerator/CodeTypeReferenceBuilder.cs +++ b/src/PublicApiGenerator/CodeTypeReferenceBuilder.cs @@ -144,6 +144,11 @@ static string GetTypeNameCore(TypeReference type, IEnumerator nullability return GetTypeName(array.ElementType, nullabilityMap, NullableMode.Default, disableNested) + "[]"; } + if (type is PointerType pointer) + { + return CSharpTypeKeyword.Get(GetTypeName(pointer.ElementType, nullabilityMap, NullableMode.Default, disableNested)) + "*"; + } + if (!type.IsNested || disableNested) { var name = type is RequiredModifierType modType ? modType.ElementType.Name : type.Name; diff --git a/src/PublicApiGeneratorTests/Field_modifiers.cs b/src/PublicApiGeneratorTests/Field_modifiers.cs index 489a88d..9a00e3f 100644 --- a/src/PublicApiGeneratorTests/Field_modifiers.cs +++ b/src/PublicApiGeneratorTests/Field_modifiers.cs @@ -77,8 +77,8 @@ public void Include_unsafe_fields() { public class ClassWithUnsafeFields { - protected unsafe System.Void* UnsafeProtectedField; - public unsafe System.Void* UnsafePublicField; + protected unsafe void* UnsafeProtectedField; + public unsafe void* UnsafePublicField; public ClassWithUnsafeFields() { } } }"); diff --git a/src/PublicApiGeneratorTests/Method_modifiers.cs b/src/PublicApiGeneratorTests/Method_modifiers.cs index 09045c2..dc7f436 100644 --- a/src/PublicApiGeneratorTests/Method_modifiers.cs +++ b/src/PublicApiGeneratorTests/Method_modifiers.cs @@ -1,4 +1,4 @@ -using PublicApiGeneratorTests.Examples; +using PublicApiGeneratorTests.Examples; using Xunit; namespace PublicApiGeneratorTests @@ -98,7 +98,7 @@ public void Should_output_unsafe_modifier() public class ClassWithUnsafeMethod { public ClassWithUnsafeMethod() { } - public unsafe System.Void* DoSomething() { } + public unsafe void* DoSomething() { } } }"); } @@ -175,4 +175,4 @@ public class ClassWithUnsafeMethod // ReSharper restore UnusedMemberHierarchy.Global // ReSharper restore UnusedMember.Global // ReSharper restore ClassNeverInstantiated.Global -} \ No newline at end of file +} From 955f5f239bdb835612c7c23c374263b9c3bff8e7 Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Mon, 4 Nov 2019 10:15:11 +0100 Subject: [PATCH 4/4] Moar test cases --- src/PublicApiGeneratorTests/Field_modifiers.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PublicApiGeneratorTests/Field_modifiers.cs b/src/PublicApiGeneratorTests/Field_modifiers.cs index 9a00e3f..b15eed6 100644 --- a/src/PublicApiGeneratorTests/Field_modifiers.cs +++ b/src/PublicApiGeneratorTests/Field_modifiers.cs @@ -78,7 +78,10 @@ public void Include_unsafe_fields() public class ClassWithUnsafeFields { protected unsafe void* UnsafeProtectedField; + public unsafe byte* UnsafePublicByteField; public unsafe void* UnsafePublicField; + public unsafe int* UnsafePublicIntField; + public unsafe long* UnsafePublicLongField; public ClassWithUnsafeFields() { } } }"); @@ -115,6 +118,9 @@ public class ClassWithConstFields public class ClassWithUnsafeFields { public unsafe void* UnsafePublicField; + public unsafe byte* UnsafePublicByteField; + public unsafe int* UnsafePublicIntField; + public unsafe long* UnsafePublicLongField; protected unsafe void* UnsafeProtectedField; } }