Skip to content

Commit c117bc5

Browse files
committed
Rely on enum fields never being trimmed
1 parent 06b54c3 commit c117bc5

File tree

4 files changed

+7
-248
lines changed

4 files changed

+7
-248
lines changed

src/Microsoft.OpenApi/Extensions/EnumExtensions.cs

Lines changed: 2 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Linq;
77
using System.Reflection;
88
using Microsoft.OpenApi.Attributes;
9-
using Microsoft.OpenApi.Models;
109

1110
namespace Microsoft.OpenApi.Extensions
1211
{
@@ -23,12 +22,11 @@ public static class EnumExtensions
2322
/// <returns>
2423
/// The attribute of the specified type or null.
2524
/// </returns>
26-
[Obsolete("GetAttributeOfType<T> is deprecated and will be removed in a future release.")]
27-
[RequiresUnreferencedCode("GetAttributeOfType is not trim-compatible. Recommended to use native AoT-friendly type-specific overloads of GetDisplayName instead.")]
25+
[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Fields are never trimmed for enum types.")]
2826
public static T GetAttributeOfType<T>(this Enum enumValue) where T : Attribute
2927
{
3028
var type = enumValue.GetType();
31-
var memInfo = type.GetMember(enumValue.ToString()).First();
29+
var memInfo = type.GetField(enumValue.ToString(), BindingFlags.Public | BindingFlags.Static);
3230
var attributes = memInfo.GetCustomAttributes<T>(false);
3331
return attributes.FirstOrDefault();
3432
}
@@ -41,96 +39,10 @@ public static T GetAttributeOfType<T>(this Enum enumValue) where T : Attribute
4139
/// Use <see cref="DisplayAttribute"/> if exists.
4240
/// Otherwise, use the standard string representation.
4341
/// </returns>
44-
[Obsolete("Use native AoT-friendly type-specific overloads GetDisplayName methods instead.")]
45-
[RequiresUnreferencedCode("GetAttributeOfType is not trim-compatible. Recommended to use native AoT-friendly type-specific overloads of GetDisplayName instead.")]
4642
public static string GetDisplayName(this Enum enumValue)
4743
{
4844
var attribute = enumValue.GetAttributeOfType<DisplayAttribute>();
4945
return attribute == null ? enumValue.ToString() : attribute.Name;
5046
}
51-
52-
/// <summary>
53-
/// Gets the enum display for name <see cref="ParameterStyle" /> without the use of reflection.
54-
/// </summary>
55-
/// <param name="parameterStyle">The enum value.</param>
56-
/// <returns>The display string to use.</returns>
57-
internal static string GetDisplayName(this ParameterStyle parameterStyle) => parameterStyle switch
58-
{
59-
ParameterStyle.Matrix => "matrix",
60-
ParameterStyle.Label => "label",
61-
ParameterStyle.Form => "form",
62-
ParameterStyle.Simple => "simple",
63-
ParameterStyle.SpaceDelimited => "spaceDelimited",
64-
ParameterStyle.PipeDelimited => "pipeDelimited",
65-
ParameterStyle.DeepObject => "deepObject",
66-
_ => throw new InvalidOperationException($"Unknown parameter style: {parameterStyle}")
67-
};
68-
69-
/// <summary>
70-
/// Gets the enum display for name <see cref="ParameterLocation" /> without the use of reflection.
71-
/// </summary>
72-
/// <param name="parameterLocation">The enum value.</param>
73-
/// <returns>The display string to use.</returns>
74-
public static string GetDisplayName(this ParameterLocation parameterLocation) => parameterLocation switch
75-
{
76-
ParameterLocation.Query => "query",
77-
ParameterLocation.Header => "header",
78-
ParameterLocation.Path => "path",
79-
ParameterLocation.Cookie => "cookie",
80-
_ => throw new InvalidOperationException($"Unknown parameter location: {parameterLocation}")
81-
};
82-
83-
/// <summary>
84-
/// Gets the enum display for name <see cref="ReferenceType" /> without the use of reflection.
85-
/// </summary>
86-
/// <param name="referenceType">The enum value.</param>
87-
/// <returns>The display string to use.</returns>
88-
internal static string GetDisplayName(this ReferenceType referenceType) => referenceType switch
89-
{
90-
ReferenceType.Schema => "schemas",
91-
ReferenceType.Response => "responses",
92-
ReferenceType.Parameter => "parameters",
93-
ReferenceType.Example => "examples",
94-
ReferenceType.RequestBody => "requestBodies",
95-
ReferenceType.Header => "headers",
96-
ReferenceType.SecurityScheme => "securitySchemes",
97-
ReferenceType.Link => "links",
98-
ReferenceType.Callback => "callbacks",
99-
ReferenceType.Tag => "tags",
100-
ReferenceType.Path => "path",
101-
_ => throw new InvalidOperationException($"Unknown reference type: {referenceType}")
102-
};
103-
104-
/// <summary>
105-
/// Gets the enum display for name <see cref="OperationType" /> without the use of reflection.
106-
/// </summary>
107-
/// <param name="operationType">The enum value.</param>
108-
/// <returns>The display string to use.</returns>
109-
internal static string GetDisplayName(this OperationType operationType) => operationType switch
110-
{
111-
OperationType.Get => "get",
112-
OperationType.Put => "put",
113-
OperationType.Post => "post",
114-
OperationType.Delete => "delete",
115-
OperationType.Options => "options",
116-
OperationType.Head => "head",
117-
OperationType.Patch => "patch",
118-
OperationType.Trace => "trace",
119-
_ => throw new InvalidOperationException($"Unknown operation type: {operationType}")
120-
};
121-
122-
/// <summary>
123-
/// Gets the enum display for name <see cref="SecuritySchemeType" /> without the use of reflection.
124-
/// </summary>
125-
/// <param name="securitySchemeType">The enum value.</param>
126-
/// <returns>The display string to use.</returns>
127-
internal static string GetDisplayName(this SecuritySchemeType securitySchemeType) => securitySchemeType switch
128-
{
129-
SecuritySchemeType.ApiKey => "apiKey",
130-
SecuritySchemeType.Http => "http",
131-
SecuritySchemeType.OAuth2 => "oauth2",
132-
SecuritySchemeType.OpenIdConnect => "openIdConnect",
133-
_ => throw new InvalidOperationException($"Unknown security scheme type: {securitySchemeType}")
134-
};
13547
}
13648
}

src/Microsoft.OpenApi/Extensions/StringExtensions.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static class StringExtensions
1717
/// Gets the enum value based on the given enum type and display name.
1818
/// </summary>
1919
/// <param name="displayName">The display name.</param>
20+
[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Fields are never trimmed for enum types.")]
2021
public static T GetEnumFromDisplayName<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(this string displayName)
2122
{
2223
var type = typeof(T);
@@ -25,14 +26,12 @@ public static class StringExtensions
2526
return default;
2627
}
2728

28-
foreach (var value in Enum.GetValues(type))
29+
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))
2930
{
30-
var field = type.GetField(value.ToString());
31-
3231
var displayAttribute = (DisplayAttribute)field.GetCustomAttribute(typeof(DisplayAttribute));
3332
if (displayAttribute != null && displayAttribute.Name == displayName)
3433
{
35-
return (T)value;
34+
return (T)field.GetValue(null);
3635
}
3736
}
3837

Lines changed: 2 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Reflection.Metadata;
5-
using Microsoft.OpenApi.Attributes;
1+
using Microsoft.OpenApi.Attributes;
62
using Microsoft.OpenApi.Extensions;
7-
using Microsoft.OpenApi.Models;
83
using Xunit;
94

105
namespace Microsoft.OpenApi.Tests.Attributes
@@ -27,151 +22,7 @@ public class DisplayAttributeTests
2722
[InlineData(ApiLevel.Corporate, "corporate")]
2823
public void GetDisplayNameExtensionShouldUseDisplayAttribute(ApiLevel apiLevel, string expected)
2924
{
30-
#pragma warning disable CS0618 // Type or member is obsolete, testing obsolete behavior
31-
Assert.Equal(expected, apiLevel.GetDisplayName());
32-
#pragma warning restore CS0618 // Type or member is obsolete, testing obsolete behavior
33-
}
34-
35-
[Fact]
36-
public void GetDisplayNameWorksForAllParameterStyle()
37-
{
38-
var enumValues = new List<ParameterStyle>(Enum.GetValues<ParameterStyle>());
39-
40-
Assert.Equal("matrix", ParameterStyle.Matrix.GetDisplayName());
41-
Assert.True(enumValues.Remove(ParameterStyle.Matrix));
42-
43-
Assert.Equal("label", ParameterStyle.Label.GetDisplayName());
44-
Assert.True(enumValues.Remove(ParameterStyle.Label));
45-
46-
Assert.Equal("form", ParameterStyle.Form.GetDisplayName());
47-
Assert.True(enumValues.Remove(ParameterStyle.Form));
48-
49-
Assert.Equal("simple", ParameterStyle.Simple.GetDisplayName());
50-
Assert.True(enumValues.Remove(ParameterStyle.Simple));
51-
52-
Assert.Equal("spaceDelimited", ParameterStyle.SpaceDelimited.GetDisplayName());
53-
Assert.True(enumValues.Remove(ParameterStyle.SpaceDelimited));
54-
55-
Assert.Equal("pipeDelimited", ParameterStyle.PipeDelimited.GetDisplayName());
56-
Assert.True(enumValues.Remove(ParameterStyle.PipeDelimited));
57-
58-
Assert.Equal("deepObject", ParameterStyle.DeepObject.GetDisplayName());
59-
Assert.True(enumValues.Remove(ParameterStyle.DeepObject));
60-
61-
Assert.Empty(enumValues);
62-
}
63-
64-
[Fact]
65-
public void GetDisplayNameWorksForAllParameterLocation()
66-
{
67-
var enumValues = new List<ParameterLocation>(Enum.GetValues<ParameterLocation>());
68-
69-
Assert.Equal("query", ParameterLocation.Query.GetDisplayName());
70-
Assert.True(enumValues.Remove(ParameterLocation.Query));
71-
72-
Assert.Equal("header", ParameterLocation.Header.GetDisplayName());
73-
Assert.True(enumValues.Remove(ParameterLocation.Header));
74-
75-
Assert.Equal("path", ParameterLocation.Path.GetDisplayName());
76-
Assert.True(enumValues.Remove(ParameterLocation.Path));
77-
78-
Assert.Equal("cookie", ParameterLocation.Cookie.GetDisplayName());
79-
Assert.True(enumValues.Remove(ParameterLocation.Cookie));
80-
81-
Assert.Empty(enumValues);
82-
}
83-
84-
[Fact]
85-
public void GetDisplayNameWorksForAllReferenceType()
86-
{
87-
var enumValues = new List<ReferenceType>(Enum.GetValues<ReferenceType>());
88-
89-
Assert.Equal("schemas", ReferenceType.Schema.GetDisplayName());
90-
Assert.True(enumValues.Remove(ReferenceType.Schema));
91-
92-
Assert.Equal("responses", ReferenceType.Response.GetDisplayName());
93-
Assert.True(enumValues.Remove(ReferenceType.Response));
94-
95-
Assert.Equal("parameters", ReferenceType.Parameter.GetDisplayName());
96-
Assert.True(enumValues.Remove(ReferenceType.Parameter));
97-
98-
Assert.Equal("examples", ReferenceType.Example.GetDisplayName());
99-
Assert.True(enumValues.Remove(ReferenceType.Example));
100-
101-
Assert.Equal("requestBodies", ReferenceType.RequestBody.GetDisplayName());
102-
Assert.True(enumValues.Remove(ReferenceType.RequestBody));
103-
104-
Assert.Equal("headers", ReferenceType.Header.GetDisplayName());
105-
Assert.True(enumValues.Remove(ReferenceType.Header));
106-
107-
Assert.Equal("securitySchemes", ReferenceType.SecurityScheme.GetDisplayName());
108-
Assert.True(enumValues.Remove(ReferenceType.SecurityScheme));
109-
110-
Assert.Equal("links", ReferenceType.Link.GetDisplayName());
111-
Assert.True(enumValues.Remove(ReferenceType.Link));
112-
113-
Assert.Equal("callbacks", ReferenceType.Callback.GetDisplayName());
114-
Assert.True(enumValues.Remove(ReferenceType.Callback));
115-
116-
Assert.Equal("tags", ReferenceType.Tag.GetDisplayName());
117-
Assert.True(enumValues.Remove(ReferenceType.Tag));
118-
119-
Assert.Equal("path", ReferenceType.Path.GetDisplayName());
120-
Assert.True(enumValues.Remove(ReferenceType.Path));
121-
122-
Assert.Empty(enumValues);
123-
}
124-
125-
[Fact]
126-
public void GetDisplayNameWorksForAllOperationTypes()
127-
{
128-
var enumValues = new List<OperationType>(Enum.GetValues<OperationType>());
129-
130-
Assert.Equal("get", OperationType.Get.GetDisplayName());
131-
Assert.True(enumValues.Remove(OperationType.Get));
132-
133-
Assert.Equal("put", OperationType.Put.GetDisplayName());
134-
Assert.True(enumValues.Remove(OperationType.Put));
135-
136-
Assert.Equal("post", OperationType.Post.GetDisplayName());
137-
Assert.True(enumValues.Remove(OperationType.Post));
138-
139-
Assert.Equal("delete", OperationType.Delete.GetDisplayName());
140-
Assert.True(enumValues.Remove(OperationType.Delete));
141-
142-
Assert.Equal("options", OperationType.Options.GetDisplayName());
143-
Assert.True(enumValues.Remove(OperationType.Options));
144-
145-
Assert.Equal("head", OperationType.Head.GetDisplayName());
146-
Assert.True(enumValues.Remove(OperationType.Head));
147-
148-
Assert.Equal("patch", OperationType.Patch.GetDisplayName());
149-
Assert.True(enumValues.Remove(OperationType.Patch));
150-
151-
Assert.Equal("trace", OperationType.Trace.GetDisplayName());
152-
Assert.True(enumValues.Remove(OperationType.Trace));
153-
154-
Assert.Empty(enumValues);
155-
}
156-
157-
[Fact]
158-
public void GetDisplayNameWorksForAllSecuritySchemeTypes()
159-
{
160-
var enumValues = new List<SecuritySchemeType>(Enum.GetValues<SecuritySchemeType>());
161-
162-
Assert.Equal("apiKey", SecuritySchemeType.ApiKey.GetDisplayName());
163-
Assert.True(enumValues.Remove(SecuritySchemeType.ApiKey));
164-
165-
Assert.Equal("http", SecuritySchemeType.Http.GetDisplayName());
166-
Assert.True(enumValues.Remove(SecuritySchemeType.Http));
167-
168-
Assert.Equal("oauth2", SecuritySchemeType.OAuth2.GetDisplayName());
169-
Assert.True(enumValues.Remove(SecuritySchemeType.OAuth2));
170-
171-
Assert.Equal("openIdConnect", SecuritySchemeType.OpenIdConnect.GetDisplayName());
172-
Assert.True(enumValues.Remove(SecuritySchemeType.OpenIdConnect));
173-
174-
Assert.Empty(enumValues);
25+
Assert.Equal(expected, apiLevel.GetDisplayName());
17526
}
17627
}
17728
}

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,8 @@ namespace Microsoft.OpenApi.Extensions
249249
{
250250
public static class EnumExtensions
251251
{
252-
[System.Obsolete("GetAttributeOfType<T> is deprecated and will be removed in a future release.")]
253252
public static T GetAttributeOfType<T>(this System.Enum enumValue)
254253
where T : System.Attribute { }
255-
public static string GetDisplayName(this Microsoft.OpenApi.Models.ParameterLocation parameterLocation) { }
256-
[System.Obsolete("Use native AoT-friendly type-specific overloads GetDisplayName methods instead.")]
257254
public static string GetDisplayName(this System.Enum enumValue) { }
258255
}
259256
public static class OpenApiElementExtensions

0 commit comments

Comments
 (0)