Skip to content

Commit b846d57

Browse files
Add validation for Params* attributes on init-only properties, fix #1877
1 parent 4b6e83d commit b846d57

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

src/BenchmarkDotNet/Extensions/ReflectionExtensions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ internal static bool HasAttribute<T>(this MemberInfo? memberInfo) where T : Attr
1919

2020
internal static bool IsNullable(this Type type) => Nullable.GetUnderlyingType(type) != null;
2121

22+
public static bool IsInitOnly(this PropertyInfo propertyInfo)
23+
{
24+
var setMethodReturnParameter = propertyInfo.SetMethod?.ReturnParameter;
25+
if (setMethodReturnParameter == null)
26+
return false;
27+
28+
var isExternalInitType = typeof(System.Runtime.CompilerServices.Unsafe).Assembly
29+
.GetType("System.Runtime.CompilerServices.IsExternalInit");
30+
if (isExternalInitType == null)
31+
return false;
32+
33+
return setMethodReturnParameter.GetRequiredCustomModifiers().Contains(isExternalInitType);
34+
}
35+
2236
/// <summary>
2337
/// returns type name which can be used in generated C# code
2438
/// </summary>

src/BenchmarkDotNet/Validators/ParamsValidator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ private IEnumerable<ValidationError> Validate(Type type)
4646
yield return new ValidationError(TreatsWarningsAsErrors,
4747
$"Unable to use {name} with {attributeString} because it's a {modifier} field. Please, remove the {modifier} modifier.");
4848
}
49+
50+
if (memberInfo is PropertyInfo propertyInfo && propertyInfo.IsInitOnly())
51+
{
52+
yield return new ValidationError(TreatsWarningsAsErrors,
53+
$"Unable to use {name} with {attributeString} because it's init-only. Please, provide a public setter.");
54+
}
4955
}
5056
}
5157
}

tests/BenchmarkDotNet.Tests/Validators/ParamsValidatorTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,5 +176,31 @@ public class PropMultiple4 : Base
176176
[ParamsSource(nameof(Source))]
177177
public bool Input { get; set; }
178178
}
179+
180+
#if NET5_0_OR_GREATER
181+
182+
[Fact] public void InitOnly1Test() => Check<InitOnly1>(nameof(InitOnly1.Input), "init-only", P);
183+
[Fact] public void InitOnly2Test() => Check<InitOnly2>(nameof(InitOnly2.Input), "init-only", Pa);
184+
[Fact] public void InitOnly3Test() => Check<InitOnly3>(nameof(InitOnly3.Input), "init-only", Ps);
185+
186+
public class InitOnly1 : Base
187+
{
188+
[Params(false, true)]
189+
public bool Input { get; init; }
190+
}
191+
192+
public class InitOnly2 : Base
193+
{
194+
[ParamsAllValues]
195+
public bool Input { get; init; }
196+
}
197+
198+
public class InitOnly3 : Base
199+
{
200+
[ParamsSource(nameof(Source))]
201+
public bool Input { get; init; }
202+
}
203+
204+
#endif
179205
}
180206
}

0 commit comments

Comments
 (0)