Skip to content

Commit 4f2f801

Browse files
committed
Enable property visibility tests in source-gen mode
1 parent 9fb28c8 commit 4f2f801

File tree

64 files changed

+4113
-3019
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+4113
-3019
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
6+
namespace System.Text.Json
7+
{
8+
internal static partial class JsonHelpers
9+
{
10+
/// <summary>
11+
/// Emulates Dictionary.TryAdd on netstandard.
12+
/// </summary>
13+
public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, in TKey key, in TValue value) where TKey : notnull
14+
{
15+
#if NETSTANDARD2_0 || NETFRAMEWORK
16+
if (!dictionary.ContainsKey(key))
17+
{
18+
dictionary[key] = value;
19+
return true;
20+
}
21+
22+
return false;
23+
#else
24+
return dictionary.TryAdd(key, value);
25+
#endif
26+
}
27+
}
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
using System.Reflection;
6+
7+
namespace System.Text.Json.Reflection
8+
{
9+
internal static partial class ReflectionExtensions
10+
{
11+
public static bool IsVirtual(this PropertyInfo? propertyInfo)
12+
{
13+
Debug.Assert(propertyInfo != null);
14+
return propertyInfo != null && (propertyInfo.GetMethod?.IsVirtual == true || propertyInfo.SetMethod?.IsVirtual == true);
15+
}
16+
}
17+
}

src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.Text.Json.Serialization;
6-
using System.Text.Json.SourceGeneration.Reflection;
6+
using System.Text.Json.Reflection;
77

88
namespace System.Text.Json.SourceGeneration
99
{
@@ -19,6 +19,8 @@ internal sealed class ContextGenerationSpec
1919

2020
public List<TypeGenerationSpec> RootSerializableTypes { get; } = new();
2121

22+
public HashSet<TypeGenerationSpec>? NullableUnderlyingTypes { get; } = new();
23+
2224
public List<string> ContextClassDeclarationList { get; init; }
2325

2426
/// <summary>

src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs

Lines changed: 190 additions & 199 deletions
Large diffs are not rendered by default.

src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs

Lines changed: 153 additions & 46 deletions
Large diffs are not rendered by default.

src/libraries/System.Text.Json/gen/JsonSourceGenerator.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Diagnostics;
66
using System.Linq;
77
using System.Reflection;
8-
using System.Text.Json.SourceGeneration.Reflection;
8+
using System.Text.Json.Reflection;
99
using Microsoft.CodeAnalysis;
1010
using Microsoft.CodeAnalysis.CSharp;
1111
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -37,6 +37,12 @@ public void Initialize(GeneratorInitializationContext context)
3737
/// <param name="executionContext"></param>
3838
public void Execute(GeneratorExecutionContext executionContext)
3939
{
40+
#if LAUNCH_DEBUGGER
41+
if (!Diagnostics.Debugger.IsAttached)
42+
{
43+
Diagnostics.Debugger.Launch();
44+
}
45+
#endif
4046
SyntaxReceiver receiver = (SyntaxReceiver)executionContext.SyntaxReceiver;
4147
List<ClassDeclarationSyntax>? contextClasses = receiver.ClassDeclarationSyntaxList;
4248
if (contextClasses == null)
@@ -55,12 +61,6 @@ public void Execute(GeneratorExecutionContext executionContext)
5561
}
5662
}
5763

58-
/// <summary>
59-
/// Helper for unit tests.
60-
/// </summary>
61-
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName, p => p.Type);
62-
private List<TypeGenerationSpec>? _rootTypes;
63-
6464
private sealed class SyntaxReceiver : ISyntaxReceiver
6565
{
6666
public List<ClassDeclarationSyntax>? ClassDeclarationSyntaxList { get; private set; }
@@ -73,5 +73,11 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
7373
}
7474
}
7575
}
76+
77+
/// <summary>
78+
/// Helper for unit tests.
79+
/// </summary>
80+
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName, p => p.Type);
81+
private List<TypeGenerationSpec>? _rootTypes;
7682
}
7783
}

src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,29 @@ namespace System.Text.Json.SourceGeneration
99
[DebuggerDisplay("Name={Name}, Type={TypeMetadata}")]
1010
internal sealed class PropertyGenerationSpec
1111
{
12-
/// <summary>
13-
/// The CLR name of the property.
14-
/// </summary>
1512
public string ClrName { get; init; }
1613

1714
/// <summary>
1815
/// Is this a property or a field?
1916
/// </summary>
2017
public bool IsProperty { get; init; }
2118

19+
public bool IsPublic { get; init; }
20+
21+
public bool IsVirtual { get; init; }
22+
2223
/// <summary>
2324
/// The property name specified via JsonPropertyNameAttribute, if available.
2425
/// </summary>
2526
public string? JsonPropertyName { get; init; }
2627

28+
/// <summary>
29+
/// The pre-determined JSON property name, accounting for <see cref="JsonNamingPolicy"/>
30+
/// specified ahead-of-time via <see cref="JsonSourceGenerationOptionsAttribute"/>.
31+
/// Only used in fast-path serialization logic.
32+
/// </summary>
33+
public string RuntimePropertyName { get; init; }
34+
2735
/// <summary>
2836
/// Whether the property has a set method.
2937
/// </summary>

src/libraries/System.Text.Json/gen/Reflection/AssemblyWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using Microsoft.CodeAnalysis;
77

8-
namespace System.Text.Json.SourceGeneration.Reflection
8+
namespace System.Text.Json.Reflection
99
{
1010
internal class AssemblyWrapper : Assembly
1111
{

src/libraries/System.Text.Json/gen/Reflection/ConstructorInfoWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Reflection;
77
using Microsoft.CodeAnalysis;
88

9-
namespace System.Text.Json.SourceGeneration.Reflection
9+
namespace System.Text.Json.Reflection
1010
{
1111
internal class ConstructorInfoWrapper : ConstructorInfo
1212
{

src/libraries/System.Text.Json/gen/Reflection/CustomAttributeDataWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Reflection;
77
using Microsoft.CodeAnalysis;
88

9-
namespace System.Text.Json.SourceGeneration.Reflection
9+
namespace System.Text.Json.Reflection
1010
{
1111
internal class CustomAttributeDataWrapper : CustomAttributeData
1212
{

src/libraries/System.Text.Json/gen/Reflection/FieldInfoWrapper.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using Microsoft.CodeAnalysis;
77
using System.Globalization;
88

9-
namespace System.Text.Json.SourceGeneration.Reflection
9+
namespace System.Text.Json.Reflection
1010
{
1111
internal class FieldInfoWrapper : FieldInfo
1212
{
@@ -33,6 +33,11 @@ public override FieldAttributes Attributes
3333
_attributes |= FieldAttributes.Static;
3434
}
3535

36+
if (_field.IsReadOnly)
37+
{
38+
_attributes |= FieldAttributes.InitOnly;
39+
}
40+
3641
switch (_field.DeclaredAccessibility)
3742
{
3843
case Accessibility.Public:
@@ -41,6 +46,9 @@ public override FieldAttributes Attributes
4146
case Accessibility.Private:
4247
_attributes |= FieldAttributes.Private;
4348
break;
49+
case Accessibility.Protected:
50+
_attributes |= FieldAttributes.Family;
51+
break;
4452
}
4553
}
4654

src/libraries/System.Text.Json/gen/Reflection/MemberInfoWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using Microsoft.CodeAnalysis;
77

8-
namespace System.Text.Json.SourceGeneration.Reflection
8+
namespace System.Text.Json.Reflection
99
{
1010
internal class MemberInfoWrapper : MemberInfo
1111
{

src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using System.Runtime.CompilerServices;
99
using Microsoft.CodeAnalysis;
1010

11-
namespace System.Text.Json.SourceGeneration.Reflection
11+
namespace System.Text.Json.Reflection
1212
{
1313
internal class MetadataLoadContextInternal
1414
{

src/libraries/System.Text.Json/gen/Reflection/MethodInfoWrapper.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Reflection;
77
using Microsoft.CodeAnalysis;
88

9-
namespace System.Text.Json.SourceGeneration.Reflection
9+
namespace System.Text.Json.Reflection
1010
{
1111
internal class MethodInfoWrapper : MethodInfo
1212
{
@@ -41,7 +41,7 @@ public override MethodAttributes Attributes
4141
_attributes |= MethodAttributes.Static;
4242
}
4343

44-
if (_method.IsVirtual)
44+
if (_method.IsVirtual || _method.IsOverride)
4545
{
4646
_attributes |= MethodAttributes.Virtual;
4747
}
@@ -54,6 +54,9 @@ public override MethodAttributes Attributes
5454
case Accessibility.Private:
5555
_attributes |= MethodAttributes.Private;
5656
break;
57+
case Accessibility.Internal:
58+
_attributes |= MethodAttributes.Assembly;
59+
break;
5760
}
5861
}
5962

src/libraries/System.Text.Json/gen/Reflection/ParameterInfoWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using Microsoft.CodeAnalysis;
77

8-
namespace System.Text.Json.SourceGeneration.Reflection
8+
namespace System.Text.Json.Reflection
99
{
1010
internal class ParameterInfoWrapper : ParameterInfo
1111
{

src/libraries/System.Text.Json/gen/Reflection/PropertyInfoWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Reflection;
77
using Microsoft.CodeAnalysis;
88

9-
namespace System.Text.Json.SourceGeneration.Reflection
9+
namespace System.Text.Json.Reflection
1010
{
1111
internal class PropertyInfoWrapper : PropertyInfo
1212
{

src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
using System.Linq;
66
using System.Reflection;
77

8-
namespace System.Text.Json.SourceGeneration.Reflection
8+
namespace System.Text.Json.Reflection
99
{
10-
internal static class ReflectionExtensions
10+
internal static partial class ReflectionExtensions
1111
{
1212
public static CustomAttributeData GetCustomAttributeData(this MemberInfo memberInfo, Type type)
1313
{

src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using Microsoft.CodeAnalysis;
77

8-
namespace System.Text.Json.SourceGeneration.Reflection
8+
namespace System.Text.Json.Reflection
99
{
1010
internal static class RoslynExtensions
1111
{

src/libraries/System.Text.Json/gen/Reflection/TypeExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Diagnostics;
55
using System.Linq;
66

7-
namespace System.Text.Json.SourceGeneration.Reflection
7+
namespace System.Text.Json.Reflection
88
{
99
internal static class TypeExtensions
1010
{

src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
using System.Reflection;
1010
using Microsoft.CodeAnalysis;
1111

12-
namespace System.Text.Json.SourceGeneration.Reflection
12+
namespace System.Text.Json.Reflection
1313
{
1414
internal class TypeWrapper : Type
1515
{
@@ -231,18 +231,32 @@ public override FieldInfo GetField(string name, BindingFlags bindingAttr)
231231

232232
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
233233
{
234-
var fields = new List<FieldInfo>();
234+
List<FieldInfo> fields = new();
235+
235236
foreach (ISymbol item in _typeSymbol.GetMembers())
236237
{
237-
// Associated Symbol checks the field is not a backingfield.
238-
if (item is IFieldSymbol field && field.AssociatedSymbol == null && !field.IsReadOnly)
238+
if (item is IFieldSymbol fieldSymbol)
239239
{
240-
if ((item.DeclaredAccessibility & Accessibility.Public) == Accessibility.Public)
240+
// Skip if:
241+
if (
242+
// this is a backing field
243+
fieldSymbol.AssociatedSymbol != null ||
244+
// we want a static field and this is not static
245+
(BindingFlags.Static & bindingAttr) != 0 && !fieldSymbol.IsStatic ||
246+
// we want an instance field and this is static or a constant
247+
(BindingFlags.Instance & bindingAttr) != 0 && (fieldSymbol.IsStatic || fieldSymbol.IsConst))
241248
{
242-
fields.Add(new FieldInfoWrapper(field, _metadataLoadContext));
249+
continue;
250+
}
251+
252+
if ((BindingFlags.Public & bindingAttr) != 0 && item.DeclaredAccessibility == Accessibility.Public ||
253+
(BindingFlags.NonPublic & bindingAttr) != 0)
254+
{
255+
fields.Add(new FieldInfoWrapper(fieldSymbol, _metadataLoadContext));
243256
}
244257
}
245258
}
259+
246260
return fields.ToArray();
247261
}
248262

@@ -303,16 +317,32 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr)
303317
// TODO: make sure to use bindingAttr for correctness. Current implementation assumes public and non-static.
304318
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
305319
{
306-
var properties = new List<PropertyInfo>();
320+
List<PropertyInfo> properties = new();
307321

308322
foreach (ISymbol item in _typeSymbol.GetMembers())
309323
{
310-
if (item is IPropertySymbol property)
324+
if (item is IPropertySymbol propertySymbol)
311325
{
312-
if ((item.DeclaredAccessibility & Accessibility.Public) == Accessibility.Public)
326+
// Skip if:
327+
if (
328+
// we want a static property and this is not static
329+
(BindingFlags.Static & bindingAttr) != 0 && !propertySymbol.IsStatic ||
330+
// we want an instance property and this is static
331+
(BindingFlags.Instance & bindingAttr) != 0 && propertySymbol.IsStatic)
313332
{
314-
properties.Add(new PropertyInfoWrapper(property, _metadataLoadContext));
333+
continue;
315334
}
335+
336+
if ((BindingFlags.Public & bindingAttr) != 0 && item.DeclaredAccessibility == Accessibility.Public ||
337+
(BindingFlags.NonPublic & bindingAttr) != 0)
338+
{
339+
properties.Add(new PropertyInfoWrapper(propertySymbol, _metadataLoadContext));
340+
}
341+
342+
//if ((item.DeclaredAccessibility & Accessibility.Public) == Accessibility.Public)
343+
//{
344+
// properties.Add(new PropertyInfoWrapper(property, _metadataLoadContext));
345+
//}
316346
}
317347
}
318348

0 commit comments

Comments
 (0)