未验证 提交 97a51ccd 编写于 作者: E Eirik Tsarpalis 提交者: GitHub

Add nullable reference type annotations to System.Text.Json source gen (#79613)

* Add nullability annotaitons to sourcegen components.

* Move sourcegen testing from Roslyn4.0 to Roslyn4.4.

* Fix accessibility modifiers

* Allow source generators to multi-target

* Binplace only netstandard2.0 compiled source generators

* Use live NetCoreAppCurrent tfm

* Update Directory.Build.targets

* Pick correct analyzer asset for consumption

* Fix build

* Revert "Move sourcegen testing from Roslyn4.0 to Roslyn4.4."

This reverts commit fe7857066040ddf0ef632c135e83e49b097c28f7.

* Make analyzer P2Ps choose the right asset

* PR feedback

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

* Make source generator target an LKG

* Update project-guidelines.md
Co-authored-by: NViktor Hofer <viktor.hofer@microsoft.com>
上级 a53c6adf
......@@ -349,6 +349,7 @@
'$(IsPublishedAppTestProject)' != 'true' and
'$(IsTestSupportProject)' != 'true' and
'$(UsingMicrosoftDotNetSharedFrameworkSdk)' != 'true' and
'$(MSBuildProjectExtension)' != '.pkgproj' and
'$(UsingMicrosoftNoTargetsSdk)' != 'true' and
'$(UsingMicrosoftTraversalSdk)' != 'true'">true</IsSourceProject>
</PropertyGroup>
......
......@@ -77,7 +77,7 @@
<!-- Keep in sync as required by the Packaging SDK in Arcade. -->
<Description>$(PackageDescription)</Description>
</PropertyGroup>
<ItemDefinitionGroup>
<TargetPathWithTargetPlatformMoniker>
<IsReferenceAssemblyProject>$(IsReferenceAssemblyProject)</IsReferenceAssemblyProject>
......@@ -118,14 +118,15 @@
<_analyzerPath Condition="'$(AnalyzerLanguage)' != ''">$(_analyzerPath)/$(AnalyzerLanguage)</_analyzerPath>
</PropertyGroup>
<!-- Filter on netstandard2.0 so that generator projects can multi-target for the purpose of enabling nullable reference type compiler checks. -->
<ItemGroup>
<_AnalyzerPackFile Include="@(_BuildOutputInPackage)" IsSymbol="false" />
<_AnalyzerPackFile Include="@(_TargetPathsToSymbols)" IsSymbol="true" />
<_AnalyzerPackFile Include="@(_BuildOutputInPackage->WithMetadataValue('TargetFramework', 'netstandard2.0'))" IsSymbol="false" />
<_AnalyzerPackFile Include="@(_TargetPathsToSymbols->WithMetadataValue('TargetFramework', 'netstandard2.0'))" IsSymbol="true" />
<_AnalyzerPackFile PackagePath="$(_analyzerPath)/%(TargetPath)" />
</ItemGroup>
<Error Condition="'%(_AnalyzerPackFile.TargetFramework)' != 'netstandard2.0'"
Text="Analyzers must only target netstandard2.0 since they run in the compiler which targets netstandard2.0. The following files were found to target '%(_AnalyzerPackFile.TargetFramework)': @(_AnalyzerPackFile)" />
<Error Text="Analyzers must target netstandard2.0 since they run in the compiler which targets netstandard2.0. $(MSBuildProjectFullPath) targets '$([MSBuild]::ValueOrDefault('$(TargetFrameworks)', '$(TargetFramework)'))' instead."
Condition="'@(_AnalyzerPackFile)' == ''" />
</Target>
<!-- Allows building against source assemblies when the 'SkipUseReferenceAssembly' attribute is present on ProjectReference items. -->
......@@ -161,6 +162,35 @@
</ItemGroup>
</Target>
<!-- Filter out conflicting implicit assembly references. -->
<Target Name="FilterImplicitAssemblyReferences"
Condition="'$(DisableImplicitFrameworkReferences)' != 'true'"
DependsOnTargets="ResolveProjectReferences"
AfterTargets="ResolveTargetingPackAssets">
<ItemGroup>
<_targetingPackReferenceExclusion Include="$(TargetName)" />
<_targetingPackReferenceExclusion Include="@(_ResolvedProjectReferencePaths->Metadata('Filename'))" />
<_targetingPackReferenceExclusion Include="@(DefaultReferenceExclusion)" />
</ItemGroup>
<!-- Filter out shims from the targeting pack references as an opt-in. -->
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
'$(SkipTargetingPackShimReferences)' == 'true'">
<_targetingPackReferenceExclusion Include="@(NetFxReference)" />
<_targetingPackReferenceExclusion Include="netstandard" />
</ItemGroup>
<ItemGroup>
<_targetingPackReferenceWithProjectName Include="@(Reference->WithMetadataValue('ExternallyResolved', 'true')->Metadata('Filename'))"
OriginalIdentity="%(Identity)" />
<_targetingPackIncludedReferenceWithProjectName Include="@(_targetingPackReferenceWithProjectName)"
Exclude="@(_targetingPackReferenceExclusion)" />
<_targetingPackExcludedReferenceWithProjectName Include="@(_targetingPackReferenceWithProjectName)"
Exclude="@(_targetingPackIncludedReferenceWithProjectName)" />
<Reference Remove="@(_targetingPackExcludedReferenceWithProjectName->Metadata('OriginalIdentity'))" />
</ItemGroup>
</Target>
<!--
Arcade SDK versioning is defined by static properties in a targets file: work around this by
moving properties based on versioning into a target.
......
......@@ -190,6 +190,8 @@ All test outputs should be under
In the gen directory any source generator related to the assembly should exist. This does not mean the source generator is only used for that assembly only that it is conceptually apart of that assembly. For example, the assembly may provide attributes or low-level types the source generator uses.
To consume a source generator, simply add a `<ProjectReference Include="..." ReferenceOutputAssembly="false" OutputItemType="Analyzer" />` item to the project, usually next to the `Reference` and `ProjectReference` items.
A source generator must target `netstandard2.0` as such assemblies are loaded into the compiler's process which might run on either .NET Framework or modern .NET depending on the tooling being used (CLI vs Visual Studio). While that's true, a source project can still multi-target and include `$(NetCoreAppToolCurrent)` (which is the latest non live-built .NETCoreApp tfm that is supported by the SDK) to benefit from the ehancanced nullable reference type warnings emitted by the compiler. For an example see [System.Text.Json's roslyn4.4 source generator](/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.Roslyn4.4.csproj). While the repository's infrastructure makes sure that only the source generator's `netstandard2.0` build output is included in packages, to consume such a multi-targeting source generator via a `ProjectReference` (as described above), you need to add the `ReferringTargetFramework=netstandard2.0` metadata to the ProjectReference item to guarantee that the netstandard2.0 asset is chosen.
## Facades
Facade are unique in that they don't have any code and instead are generated by finding a contract reference assembly with the matching identity and generating type forwards for all the types to where they live in the implementation assemblies (aka facade seeds). There are also partial facades which contain some type forwards as well as some code definitions. All the various build configurations should be contained in the one csproj file per library.
......
......@@ -55,7 +55,7 @@
The exact version is a moving target until we ship.
It should never go ahead of the Roslyn version included in the SDK version in dotnet/arcade's global.json to avoid causing breaks in product construction.
-->
<MicrosoftCodeAnalysisVersion_4_4>4.4.0-2.22423.18</MicrosoftCodeAnalysisVersion_4_4>
<MicrosoftCodeAnalysisVersion_4_4>4.4.0</MicrosoftCodeAnalysisVersion_4_4>
<!-- Compatibility with the latest Visual Studio Preview release -->
<!--
The exact version is always a moving target. This version should never go ahead of the version of Roslyn that is included in the most recent
......@@ -64,7 +64,7 @@
When we are building from source, we care more about reducing pre-built requirements than inner-loop dev experience, so we update this to be the same version
as MicrosoftCodeAnalysisVersion.
-->
<MicrosoftCodeAnalysisVersion_LatestVS>4.4.0-2.22423.18</MicrosoftCodeAnalysisVersion_LatestVS>
<MicrosoftCodeAnalysisVersion_LatestVS>4.4.0</MicrosoftCodeAnalysisVersion_LatestVS>
<MicrosoftCodeAnalysisVersion_LatestVS Condition="'$(DotNetBuildFromSource)' == 'true'">$(MicrosoftCodeAnalysisVersion)</MicrosoftCodeAnalysisVersion_LatestVS>
<!-- Some of the analyzer dependencies used by ILLink project -->
<MicrosoftCodeAnalysisCSharpAnalyzerTestingXunitVersion>1.0.1-beta1.21265.1</MicrosoftCodeAnalysisCSharpAnalyzerTestingXunitVersion>
......
......@@ -150,7 +150,8 @@
<Target Name="IncludeAnalyzersInPackage"
Condition="'@(ProjectReference)' != '' and @(ProjectReference->AnyHaveMetadataValue('PackAsAnalyzer', 'true'))">
<MSBuild Projects="@(ProjectReference->WithMetadataValue('PackAsAnalyzer', 'true'))"
Targets="GetAnalyzerPackFiles">
Targets="GetAnalyzerPackFiles"
RemoveProperties="SetTargetFramework">
<Output TaskParameter="TargetOutputs" ItemName="_AnalyzerFile" />
</MSBuild>
......
......@@ -19,7 +19,7 @@
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
'$(TargetFrameworkVersion)' == 'v$(NetCoreAppCurrentVersion)'">
<UseLocalTargetingRuntimePack Condition="'$(UseLocalTargetingRuntimePack)' == ''">true</UseLocalTargetingRuntimePack>
<UseLocalAppHostPack Condition="'$(UseLocalAppHostPack)' == ''">true</UseLocalAppHostPack>
<UseLocalAppHostPack Condition="'$(UseLocalAppHostPack)' == ''">$(UseLocalTargetingRuntimePack)</UseLocalAppHostPack>
<EnableTargetingPackDownload>false</EnableTargetingPackDownload>
<!-- TODO: Enable when a 8.0.100 SDK is consumed
<EnableRuntimePackDownload>false</EnableRuntimePackDownload>
......@@ -171,33 +171,4 @@
Condition="'%(RuntimeFramework.FrameworkName)' == '$(LocalFrameworkOverrideName)'" />
</ItemGroup>
</Target>
<!-- Filter out conflicting implicit assembly references. -->
<Target Name="FilterImplicitAssemblyReferences"
Condition="'$(DisableImplicitFrameworkReferences)' != 'true'"
DependsOnTargets="ResolveProjectReferences"
AfterTargets="ResolveTargetingPackAssets">
<ItemGroup>
<_targetingPackReferenceExclusion Include="$(TargetName)" />
<_targetingPackReferenceExclusion Include="@(_ResolvedProjectReferencePaths->Metadata('Filename'))" />
<_targetingPackReferenceExclusion Include="@(DefaultReferenceExclusion)" />
</ItemGroup>
<!-- Filter out shims from the targeting pack references as an opt-in. -->
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
'$(SkipTargetingPackShimReferences)' == 'true'">
<_targetingPackReferenceExclusion Include="@(NetFxReference)" />
<_targetingPackReferenceExclusion Include="netstandard" />
</ItemGroup>
<ItemGroup>
<_targetingPackReferenceWithProjectName Include="@(Reference->WithMetadataValue('ExternallyResolved', 'true')->Metadata('Filename'))"
OriginalIdentity="%(Identity)" />
<_targetingPackIncludedReferenceWithProjectName Include="@(_targetingPackReferenceWithProjectName)"
Exclude="@(_targetingPackReferenceExclusion)" />
<_targetingPackExcludedReferenceWithProjectName Include="@(_targetingPackReferenceWithProjectName)"
Exclude="@(_targetingPackIncludedReferenceWithProjectName)" />
<Reference Remove="@(_targetingPackExcludedReferenceWithProjectName->Metadata('OriginalIdentity'))" />
</ItemGroup>
</Target>
</Project>
......@@ -36,10 +36,10 @@ public SyntaxTreeInfo(SyntaxTree tree, bool containsGlobalAliases, bool contains
ContainsAttributeList = containsAttributeList;
}
public bool Equals(SyntaxTreeInfo other)
public bool Equals(SyntaxTreeInfo? other)
=> Tree == other?.Tree;
public override bool Equals(object obj)
public override bool Equals(object? obj)
=> this.Equals(obj as SyntaxTreeInfo);
public override int GetHashCode()
......
......@@ -55,6 +55,8 @@
!$(NetCoreAppLibraryNoReference.Contains('$(AssemblyName);'))">true</IsNETCoreAppRef>
<IsNETCoreAppAnalyzer Condition="'$(IsGeneratorProject)' == 'true' and
$(NetCoreAppLibraryGenerator.Contains('$(MSBuildProjectName);'))">true</IsNETCoreAppAnalyzer>
<!-- Inbox analyzers shouldn't use the live targeting / runtime pack. They better depend on an LKG to avoid layering concerns. -->
<UseLocalTargetingRuntimePack Condition="'$(IsNETCoreAppAnalyzer)' == 'true'">false</UseLocalTargetingRuntimePack>
<!-- By default, disable implicit framework references for NetCoreAppCurrent libraries. -->
<DisableImplicitFrameworkReferences Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '$(NETCoreAppCurrentVersion)')) and
......@@ -95,8 +97,10 @@
<RuntimePath>$(LibrariesAllBinArtifactsPath)</RuntimePath>
</BinPlaceTargetFrameworks>
<!-- Source generator projects might multi-target. Make sure that only the netstandard2.0 compiled assets get binplaced. -->
<BinPlaceDir Include="$(MicrosoftNetCoreAppRefPackDir)analyzers\dotnet\$(AnalyzerLanguage)"
Condition="'$(IsNETCoreAppAnalyzer)' == 'true'" />
Condition="'$(IsNETCoreAppAnalyzer)' == 'true' and
'$(TargetFramework)' == 'netstandard2.0'" />
<!-- Setup the shared framework directory for testing -->
<BinPlaceTargetFrameworks Include="$(NetCoreAppCurrent)-$(TargetOS)">
......
......@@ -41,9 +41,14 @@ internal static partial class ReflectionExtensions
public static Type? GetCompatibleGenericBaseClass(
this Type type,
Type baseType,
Type? baseType,
bool sourceGenType = false)
{
if (baseType is null)
{
return null;
}
Debug.Assert(baseType.IsGenericType);
Debug.Assert(!baseType.IsInterface);
Debug.Assert(baseType == baseType.GetGenericTypeDefinition());
......
......@@ -43,7 +43,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.Json", "ref\Sys
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.Json", "src\System.Text.Json.csproj", "{1285FF43-F491-4BE0-B92C-37DA689CBD4B}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "System.Text.Json.FSharp.Tests", "tests\System.Text.Json.FSharp.Tests\System.Text.Json.FSharp.Tests.fsproj", "{5720BF06-2031-4AD8-B9B4-31A01E27ABB8}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "System.Text.Json.FSharp.Tests", "tests\System.Text.Json.FSharp.Tests\System.Text.Json.FSharp.Tests.fsproj", "{5720BF06-2031-4AD8-B9B4-31A01E27ABB8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.Json.TestLibrary.Roslyn3.11", "tests\System.Text.Json.SourceGeneration.TestLibrary\System.Text.Json.TestLibrary.Roslyn3.11.csproj", "{5C0CE30B-DD4A-4F7A-87C0-5243F0C86885}"
EndProject
......@@ -199,35 +199,35 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{102945CA-3736-4B2C-8E68-242A0B247F2B} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{5720BF06-2031-4AD8-B9B4-31A01E27ABB8} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{5C0CE30B-DD4A-4F7A-87C0-5243F0C86885} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{FCA21178-0411-45D6-B597-B7BE145CEE33} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{66AD4B7E-CF15-4A8F-8BF8-7E1BC6176D07} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{33599A6C-F340-4E1B-9B4D-CB8946C22140} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{256A4653-4287-44B3-BDEF-67FC1522ED2F} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{F6A18EB5-A8CC-4A39-9E85-5FA226019C3D} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{A0178BAA-A1AF-4C69-8E4A-A700A2723DDC} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{73D5739C-E382-4E22-A7D3-B82705C58C74} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{E9AA0AEB-AEAE-4B28-8D4D-17A6D7C89D17} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{282400DF-F3D8-4419-90F1-1E2F2D8B760C} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{6E9E4359-44F8-45AA-AEC5-D0F9FFBB13D6} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{09F77672-101E-4495-9D88-29376919C121} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{BE27618A-2916-4269-9AD5-6BC5EDC32B30} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{1C8262DB-7355-40A8-A2EC-4EED7363134A} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{C2C7BA09-F9EE-4E43-8EE4-871CC000342C} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{4774F56D-16A8-4ABB-8C73-5F57609F1773} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{D05FD93A-BC51-466E-BD56-3F3D6BBE6B06} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{B6D364E7-E5DB-4CF4-B87F-3CEDA3FF7478} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{B815304D-502E-402C-ACE1-878DB4985CCC} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{E4B72517-C694-486A-950E-6AB03C651FDC} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{FAB4FFF2-964D-45FF-89CC-8BB9CE618ED1} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{C56337BB-8CBC-4EE5-AB4D-8BB0A922813E} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{7015E94D-D20D-48C8-86D7-6A996BE99E0E} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{E9AA0AEB-AEAE-4B28-8D4D-17A6D7C89D17} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{6E9E4359-44F8-45AA-AEC5-D0F9FFBB13D6} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{1C8262DB-7355-40A8-A2EC-4EED7363134A} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{D05FD93A-BC51-466E-BD56-3F3D6BBE6B06} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{9BCCDA15-8907-4AE3-8871-2F17775DDE4C} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{1285FF43-F491-4BE0-B92C-37DA689CBD4B} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{B815304D-502E-402C-ACE1-878DB4985CCC} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{E4B72517-C694-486A-950E-6AB03C651FDC} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{04AEB008-EE4F-44DE-A361-2DBD2D0FD6A4} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{6485EED4-C313-4551-9865-8ADCED603629} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{143AFE8A-3490-444C-A82D-6A375EB59F01} = {F254F143-4704-4432-9995-20D87FA8BF8D}
{7015E94D-D20D-48C8-86D7-6A996BE99E0E} = {0371C5D8-D5F5-4747-9810-D91D71D8C0E4}
{1285FF43-F491-4BE0-B92C-37DA689CBD4B} = {E49881A9-09F6-442F-9E1D-6D87F5F837F1}
{5720BF06-2031-4AD8-B9B4-31A01E27ABB8} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{5C0CE30B-DD4A-4F7A-87C0-5243F0C86885} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{FCA21178-0411-45D6-B597-B7BE145CEE33} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{66AD4B7E-CF15-4A8F-8BF8-7E1BC6176D07} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{33599A6C-F340-4E1B-9B4D-CB8946C22140} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{256A4653-4287-44B3-BDEF-67FC1522ED2F} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{F6A18EB5-A8CC-4A39-9E85-5FA226019C3D} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
{A0178BAA-A1AF-4C69-8E4A-A700A2723DDC} = {E07C6980-EB71-4D19-A80A-7BEB80B635B1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5868B757-D821-41FC-952E-2113A0519506}
......
......@@ -16,17 +16,17 @@ namespace System.Text.Json.SourceGeneration
[DebuggerDisplay("ContextTypeRef={ContextTypeRef}")]
internal sealed class ContextGenerationSpec
{
public Location Location { get; init; }
public required Location Location { get; init; }
public JsonSourceGenerationOptionsAttribute GenerationOptions { get; init; }
public required JsonSourceGenerationOptionsAttribute GenerationOptions { get; init; }
public Type ContextType { get; init; }
public required Type ContextType { get; init; }
public List<TypeGenerationSpec> RootSerializableTypes { get; } = new();
public HashSet<TypeGenerationSpec>? ImplicitlyRegisteredTypes { get; } = new();
public HashSet<TypeGenerationSpec> ImplicitlyRegisteredTypes { get; } = new();
public List<string> ContextClassDeclarationList { get; init; }
public required List<string> ContextClassDeclarationList { get; init; }
/// <summary>
/// Types that we have initiated serialization metadata generation for. A type may be discoverable in the object graph,
......
......@@ -146,7 +146,7 @@ private void AddSource(string fileName, string source, bool isRootContextDef = f
int declarationCount = declarationList.Count;
Debug.Assert(declarationCount >= 1);
string @namespace = _currentContext.ContextType.Namespace;
string? @namespace = _currentContext.ContextType.Namespace;
bool isInGlobalNamespace = @namespace == JsonConstants.GlobalNamespaceValue;
StringBuilder sb = new(@"// <auto-generated/>
......@@ -226,8 +226,9 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec)
break;
case ClassType.Nullable:
{
source = GenerateForNullable(typeGenerationSpec);
Debug.Assert(typeGenerationSpec.NullableUnderlyingTypeMetadata != null);
source = GenerateForNullable(typeGenerationSpec);
GenerateTypeInfo(typeGenerationSpec.NullableUnderlyingTypeMetadata);
}
break;
......@@ -238,21 +239,26 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec)
break;
case ClassType.Enumerable:
{
source = GenerateForCollection(typeGenerationSpec);
Debug.Assert(typeGenerationSpec.CollectionValueTypeMetadata != null);
source = GenerateForCollection(typeGenerationSpec);
GenerateTypeInfo(typeGenerationSpec.CollectionValueTypeMetadata);
}
break;
case ClassType.Dictionary:
{
source = GenerateForCollection(typeGenerationSpec);
Debug.Assert(typeGenerationSpec.CollectionKeyTypeMetadata != null);
Debug.Assert(typeGenerationSpec.CollectionValueTypeMetadata != null);
source = GenerateForCollection(typeGenerationSpec);
GenerateTypeInfo(typeGenerationSpec.CollectionKeyTypeMetadata);
GenerateTypeInfo(typeGenerationSpec.CollectionValueTypeMetadata);
}
break;
case ClassType.Object:
{
Debug.Assert(typeGenerationSpec.PropertyGenSpecList != null);
source = GenerateForObject(typeGenerationSpec);
foreach (PropertyGenerationSpec spec in typeGenerationSpec.PropertyGenSpecList)
......@@ -492,6 +498,8 @@ private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec)
private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerationSpec)
{
Debug.Assert(typeGenerationSpec.CollectionValueTypeMetadata != null);
TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata;
Type elementType = valueTypeGenerationSpec.Type;
......@@ -542,6 +550,9 @@ private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerati
private string GenerateFastPathFuncForDictionary(TypeGenerationSpec typeGenerationSpec)
{
Debug.Assert(typeGenerationSpec.CollectionKeyTypeMetadata != null);
Debug.Assert(typeGenerationSpec.CollectionValueTypeMetadata != null);
TypeGenerationSpec keyTypeGenerationSpec = typeGenerationSpec.CollectionKeyTypeMetadata;
TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata;
......@@ -758,6 +769,8 @@ string GenerateCtorParamMetadataInitFunc(TypeGenerationSpec typeGenerationSpec)
{
const string parametersVarName = "parameters";
Debug.Assert(typeGenerationSpec.CtorParamGenSpecArray != null);
ParameterGenerationSpec[] parameters = typeGenerationSpec.CtorParamGenSpecArray;
int paramCount = parameters.Length;
Debug.Assert(paramCount > 0);
......@@ -945,6 +958,8 @@ private static bool ShouldIncludePropertyForFastPath(PropertyGenerationSpec prop
private static string GetParameterizedCtorInvocationFunc(TypeGenerationSpec typeGenerationSpec)
{
Debug.Assert(typeGenerationSpec.CtorParamGenSpecArray != null);
ParameterGenerationSpec[] parameters = typeGenerationSpec.CtorParamGenSpecArray;
int paramCount = parameters.Length;
Debug.Assert(paramCount != 0);
......@@ -1017,7 +1032,7 @@ private static string GenerateFastPathFuncForType(TypeGenerationSpec typeGenSpec
}}";
}
private static string GetEarlyNullCheckSource(bool canBeNull)
private static string? GetEarlyNullCheckSource(bool canBeNull)
{
return canBeNull
? $@"if ({ValueVarName} == null)
......@@ -1355,7 +1370,8 @@ string GetParamDefaultValueAsString(object? value, Type type, string typeRef)
{
// Roslyn gives us an instance of the underlying type, which is numerical.
#if DEBUG
Type runtimeType = _generationSpec.MetadataLoadContext.Resolve(value.GetType());
Type? runtimeType = _generationSpec.MetadataLoadContext.Resolve(value.GetType()!);
Debug.Assert(runtimeType != null);
Debug.Assert(_generationSpec.IsNumberType(runtimeType));
#endif
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//#define LAUNCH_DEBUGGER
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text.Json.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
......@@ -80,7 +75,7 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
if (IsSyntaxTargetForGeneration(context.Node))
{
ClassDeclarationSyntax classSyntax = GetSemanticTargetForGeneration(context, _cancellationToken);
ClassDeclarationSyntax? classSyntax = GetSemanticTargetForGeneration(context, _cancellationToken);
if (classSyntax != null)
{
(ClassDeclarationSyntaxList ??= new List<ClassDeclarationSyntax>()).Add(classSyntax);
......@@ -100,7 +95,7 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
cancellationToken.ThrowIfCancellationRequested();
IMethodSymbol attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeSyntax, cancellationToken).Symbol as IMethodSymbol;
IMethodSymbol? attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeSyntax, cancellationToken).Symbol as IMethodSymbol;
if (attributeSymbol == null)
{
continue;
......@@ -124,7 +119,7 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
/// <summary>
/// Helper for unit tests.
/// </summary>
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName, p => p.Type);
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName!, p => p.Type);
private List<TypeGenerationSpec>? _rootTypes;
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//#define LAUNCH_DEBUGGER
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text.Json.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
#if !ROSLYN4_4_OR_GREATER
......@@ -70,7 +64,7 @@ private void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyn
/// <summary>
/// Helper for unit tests.
/// </summary>
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName, p => p.Type);
public Dictionary<string, Type>? GetSerializableTypes() => _rootTypes?.ToDictionary(p => p.Type.FullName!, p => p.Type);
private List<TypeGenerationSpec>? _rootTypes;
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace System.Text.Json.SourceGeneration
{
internal sealed class ParameterGenerationSpec
{
public TypeGenerationSpec TypeGenerationSpec { get; init; }
public required TypeGenerationSpec TypeGenerationSpec { get; init; }
public ParameterInfo ParameterInfo { get; init; }
public required ParameterInfo ParameterInfo { get; init; }
}
}
......@@ -14,9 +14,9 @@ internal sealed class PropertyGenerationSpec
/// from the <see cref="ClrName"/> because source code might be decorated
/// with '@' for reserved keywords, e.g. public string @event { get; set; }
/// </summary>
public string NameSpecifiedInSourceCode { get; init; }
public required string NameSpecifiedInSourceCode { get; init; }
public string ClrName { get; init; }
public required string ClrName { get; init; }
/// <summary>
/// Is this a property or a field?
......@@ -45,9 +45,9 @@ internal sealed class PropertyGenerationSpec
/// specified ahead-of-time via <see cref="JsonSourceGenerationOptionsAttribute"/>.
/// Only used in fast-path serialization logic.
/// </summary>
public string RuntimePropertyName { get; init; }
public required string RuntimePropertyName { get; init; }
public string PropertyNameVarName { get; init; }
public required string PropertyNameVarName { get; init; }
/// <summary>
/// Whether the property has a set method.
......@@ -103,14 +103,14 @@ internal sealed class PropertyGenerationSpec
/// <summary>
/// Generation specification for the property's type.
/// </summary>
public TypeGenerationSpec TypeGenerationSpec { get; init; }
public required TypeGenerationSpec TypeGenerationSpec { get; init; }
/// <summary>
/// Compilable name of the property's declaring type.
/// </summary>
public string DeclaringTypeRef { get; init; }
public required string DeclaringTypeRef { get; init; }
public Type DeclaringType { get; init; }
public required Type DeclaringType { get; init; }
/// <summary>
/// Source code to instantiate design-time specified custom converter.
......
......@@ -80,12 +80,12 @@ public override ParameterInfo[] GetParameters()
return parameters.ToArray();
}
public override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
public override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
{
throw new NotSupportedException();
}
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
{
throw new NotSupportedException();
}
......
......@@ -18,10 +18,12 @@ public CustomAttributeDataWrapper(AttributeData a, MetadataLoadContextInternal m
throw new InvalidOperationException();
}
Debug.Assert(a.AttributeClass != null);
var namedArguments = new List<CustomAttributeNamedArgument>();
foreach (KeyValuePair<string, TypedConstant> na in a.NamedArguments)
{
var member = a.AttributeClass.BaseTypes().SelectMany(t => t.GetMembers(na.Key)).First();
ISymbol member = a.AttributeClass.BaseTypes().SelectMany(t => t.GetMembers(na.Key)).First();
MemberInfo memberInfo = member is IPropertySymbol
? new PropertyInfoWrapper((IPropertySymbol)member, metadataLoadContext)
......@@ -39,8 +41,8 @@ public CustomAttributeDataWrapper(AttributeData a, MetadataLoadContextInternal m
continue;
}
object value = ca.Kind == TypedConstantKind.Array ? ca.Values : ca.Value;
constructorArguments.Add(new CustomAttributeTypedArgument(ca.Type.AsType(metadataLoadContext), value));
object? value = ca.Kind == TypedConstantKind.Array ? ca.Values : ca.Value;
constructorArguments.Add(new CustomAttributeTypedArgument(ca.Type.AsType(metadataLoadContext)!, value));
}
Constructor = new ConstructorInfoWrapper(a.AttributeConstructor, metadataLoadContext);
......
......@@ -81,7 +81,7 @@ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
throw new NotImplementedException();
}
public override object GetValue(object obj)
public override object? GetValue(object? obj)
{
throw new NotImplementedException();
}
......@@ -101,7 +101,7 @@ public override bool IsDefined(Type attributeType, bool inherit)
throw new NotImplementedException();
}
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture)
public override void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, CultureInfo? culture)
{
throw new NotImplementedException();
}
......
......@@ -89,7 +89,7 @@ public override ParameterInfo[] GetParameters()
return parameters.ToArray();
}
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
public override object? Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
{
throw new NotSupportedException();
}
......
......@@ -25,7 +25,7 @@ public ParameterInfoWrapper(IParameterSymbol parameter, MetadataLoadContextInter
public override bool HasDefaultValue => _parameter.HasExplicitDefaultValue;
public override object DefaultValue => HasDefaultValue ? _parameter.ExplicitDefaultValue : null;
public override object? DefaultValue => HasDefaultValue ? _parameter.ExplicitDefaultValue : null;
public override int Position => _parameter.Ordinal;
......
......@@ -83,7 +83,7 @@ public override MethodInfo GetSetMethod(bool nonPublic)
return _property.SetMethod!.AsMethodInfo(_metadataLoadContext);
}
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
public override object? GetValue(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? index, CultureInfo? culture)
{
throw new NotSupportedException();
}
......@@ -93,7 +93,7 @@ public override bool IsDefined(Type attributeType, bool inherit)
throw new NotImplementedException();
}
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
public override void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, object?[]? index, CultureInfo? culture)
{
throw new NotSupportedException();
}
......
......@@ -11,7 +11,7 @@ namespace System.Text.Json.Reflection
{
internal static partial class ReflectionExtensions
{
public static CustomAttributeData GetCustomAttributeData(this MemberInfo memberInfo, Type type)
public static CustomAttributeData? GetCustomAttributeData(this MemberInfo memberInfo, Type type)
{
return memberInfo.CustomAttributes.FirstOrDefault(a => type.IsAssignableFrom(a.AttributeType));
}
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace System.Text.Json.Reflection
{
......@@ -11,7 +12,7 @@ public static string GetCompilableName(this Type type)
{
if (type.IsArray)
{
return GetCompilableName(type.GetElementType()) + "[]";
return GetCompilableName(type.GetElementType()!) + "[]";
}
if (type.IsGenericParameter)
......@@ -23,7 +24,7 @@ public static string GetCompilableName(this Type type)
sb.Append("global::");
string @namespace = type.Namespace;
string? @namespace = type.Namespace;
if (!string.IsNullOrEmpty(@namespace) && @namespace != JsonConstants.GlobalNamespaceValue)
{
sb.Append(@namespace);
......@@ -37,7 +38,7 @@ public static string GetCompilableName(this Type type)
static void AppendTypeChain(StringBuilder sb, Type type, Type[] genericArguments, ref int argumentIndex)
{
Type declaringType = type.DeclaringType;
Type? declaringType = type.DeclaringType;
if (declaringType != null)
{
AppendTypeChain(sb, declaringType, genericArguments, ref argumentIndex);
......@@ -75,7 +76,7 @@ public static string GetTypeInfoPropertyName(this Type type)
{
if (type.IsArray)
{
return GetTypeInfoPropertyName(type.GetElementType()) + "Array";
return GetTypeInfoPropertyName(type.GetElementType()!) + "Array";
}
else if (!type.IsGenericType)
{
......@@ -113,7 +114,7 @@ public static bool IsNullableValueType(this Type type, Type nullableOfTType, out
return false;
}
public static bool IsNullableValueType(this Type type, out Type? underlyingType)
public static bool IsNullableValueType(this Type type, [NotNullWhen(true)] out Type? underlyingType)
{
if (type.IsGenericType && type.Name.StartsWith("Nullable`1"))
{
......
......@@ -4,10 +4,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using Microsoft.CodeAnalysis;
namespace System.Text.Json.Reflection
......@@ -22,7 +23,7 @@ internal sealed class TypeWrapper : Type
private IArrayTypeSymbol? _arrayTypeSymbol;
private Type _elementType;
private Type? _elementType;
public TypeWrapper(ITypeSymbol namedTypeSymbol, MetadataLoadContextInternal metadataLoadContext)
{
......@@ -36,7 +37,7 @@ public TypeWrapper(ITypeSymbol namedTypeSymbol, MetadataLoadContextInternal meta
private string? _assemblyQualifiedName;
public override string AssemblyQualifiedName
public override string? AssemblyQualifiedName
{
get
{
......@@ -109,13 +110,13 @@ public override string AssemblyQualifiedName
}
}
public override Type BaseType => _typeSymbol.BaseType.AsType(_metadataLoadContext);
public override Type? BaseType => _typeSymbol.BaseType.AsType(_metadataLoadContext);
public override Type DeclaringType => _typeSymbol.ContainingType?.ConstructedFrom.AsType(_metadataLoadContext);
public override Type? DeclaringType => _typeSymbol.ContainingType?.ConstructedFrom.AsType(_metadataLoadContext);
private string? _fullName;
public override string FullName
public override string? FullName
{
get
{
......@@ -191,10 +192,10 @@ static void AppendContainingTypes(StringBuilder sb, ITypeSymbol typeSymbol)
public override Module Module => throw new NotImplementedException();
public override string Namespace =>
public override string? Namespace =>
IsArray ?
GetElementType().Namespace :
_typeSymbol.ContainingNamespace?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining))!;
_typeSymbol.ContainingNamespace?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining));
public override Type UnderlyingSystemType => this;
......@@ -214,17 +215,19 @@ public override string Name
public string SimpleName => _typeSymbol.Name;
private Type _enumType;
private Type? _enumType;
public override bool IsEnum
{
get
{
_enumType ??= _metadataLoadContext.Resolve(typeof(Enum));
Debug.Assert(_enumType != null);
return IsSubclassOf(_enumType);
}
}
[MemberNotNullWhen(true, nameof(_namedTypeSymbol))]
public override bool IsGenericType => _namedTypeSymbol?.IsGenericType == true;
public override bool ContainsGenericParameters
......@@ -236,7 +239,7 @@ public override bool ContainsGenericParameters
return true;
}
for (INamedTypeSymbol currentSymbol = _namedTypeSymbol; currentSymbol != null; currentSymbol = currentSymbol.ContainingType)
for (INamedTypeSymbol? currentSymbol = _namedTypeSymbol; currentSymbol != null; currentSymbol = currentSymbol.ContainingType)
{
if (currentSymbol.TypeArguments.Any(arg => arg.TypeKind == TypeKind.TypeParameter))
{
......@@ -280,6 +283,11 @@ static void AddTypeArguments(List<Type> args, INamedTypeSymbol typeSymbol, Metad
public override Type GetGenericTypeDefinition()
{
if (!IsGenericType)
{
throw new InvalidOperationException();
}
return _namedTypeSymbol.ConstructedFrom.AsType(_metadataLoadContext);
}
......@@ -415,6 +423,11 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
{
if (_namedTypeSymbol is null)
{
return Array.Empty<MethodInfo>();
}
var methods = new List<MethodInfo>();
foreach (ISymbol m in _typeSymbol.GetMembers())
{
......@@ -471,7 +484,7 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
return properties.ToArray();
}
public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
public override object InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target, object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters)
{
throw new NotSupportedException();
}
......@@ -528,18 +541,18 @@ protected override TypeAttributes GetAttributeFlagsImpl()
return _typeAttributes.Value;
}
protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers)
{
foreach (ConstructorInfo constructor in GetConstructors(bindingAttr))
{
ParameterInfo[] parameters = constructor.GetParameters();
if (parameters.Length == types.Length)
if (parameters.Length == (types?.Length ?? 0))
{
bool mismatched = false;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType != types[i])
if (parameters[i].ParameterType != types![i])
{
mismatched = true;
break;
......@@ -556,12 +569,12 @@ protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr,
return null;
}
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers)
{
throw new NotImplementedException();
}
protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[]? types, ParameterModifier[]? modifiers)
{
// TODO: performance; caching; honor bindingAttr
foreach (PropertyInfo propertyInfo in GetProperties(bindingAttr))
......@@ -585,11 +598,12 @@ protected override bool IsArrayImpl()
return _arrayTypeSymbol != null;
}
private Type _valueType;
private Type? _valueType;
protected override bool IsValueTypeImpl()
{
_valueType ??= _metadataLoadContext.Resolve(typeof(ValueType));
Debug.Assert(_valueType != null);
return IsSubclassOf(_valueType);
}
......@@ -613,9 +627,14 @@ protected override bool IsPrimitiveImpl()
throw new NotImplementedException();
}
public override bool IsAssignableFrom(Type c)
public override bool IsAssignableFrom(Type? c)
{
TypeWrapper? tr = c as TypeWrapper ?? _metadataLoadContext.Resolve(c) as TypeWrapper;
TypeWrapper? tr = c switch
{
null => null,
TypeWrapper tw => tw,
_ => _metadataLoadContext.Resolve(c) as TypeWrapper,
};
return tr is not null &&
(tr._typeSymbol.AllInterfaces.Contains(_typeSymbol, SymbolEqualityComparer.Default) ||
......@@ -636,7 +655,7 @@ public override int GetArrayRank()
return _arrayTypeSymbol.Rank;
}
public override bool Equals(object o)
public override bool Equals(object? o)
{
if (o is TypeWrapper tw)
{
......@@ -650,16 +669,20 @@ public override bool Equals(object o)
return base.Equals(o);
}
public override bool Equals(Type o)
public override bool Equals(Type? o)
{
if (o is TypeWrapper tw)
if (o != null)
{
return _typeSymbol.Equals(tw._typeSymbol, SymbolEqualityComparer.Default);
}
else if (_metadataLoadContext.Resolve(o) is TypeWrapper tww)
{
return _typeSymbol.Equals(tww._typeSymbol, SymbolEqualityComparer.Default);
if (o is TypeWrapper tw)
{
return _typeSymbol.Equals(tw._typeSymbol, SymbolEqualityComparer.Default);
}
else if (_metadataLoadContext.Resolve(o) is TypeWrapper tww)
{
return _typeSymbol.Equals(tww._typeSymbol, SymbolEqualityComparer.Default);
}
}
return base.Equals(o);
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Reflection;
using Microsoft.CodeAnalysis;
namespace System.Text.Json.SourceGeneration
{
internal sealed class SourceGenerationSpec
{
public List<ContextGenerationSpec> ContextGenerationSpecList { get; init; }
public required List<ContextGenerationSpec> ContextGenerationSpecList { get; init; }
#if DEBUG
public MetadataLoadContextInternal MetadataLoadContext { get; init; }
public required MetadataLoadContextInternal MetadataLoadContext { get; init; }
#endif
public Type BooleanType { get; init; }
public Type ByteArrayType { get; init; }
public Type CharType { get; init; }
public Type DateTimeType { private get; init; }
public Type DateTimeOffsetType { private get; init; }
public Type GuidType { private get; init; }
public Type StringType { private get; init; }
public required Type BooleanType { get; init; }
public Type? ByteArrayType { get; init; }
public required Type CharType { get; init; }
public Type? DateTimeType { private get; init; }
public Type? DateTimeOffsetType { private get; init; }
public Type? GuidType { private get; init; }
public required Type StringType { private get; init; }
public HashSet<Type> NumberTypes { private get; init; }
public required HashSet<Type> NumberTypes { private get; init; }
public bool IsStringBasedType(Type type)
=> type == StringType || type == DateTimeType || type == DateTimeOffsetType || type == GuidType;
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AnalyzerRoslynVersion>3.11</AnalyzerRoslynVersion>
<RoslynApiVersion>$(MicrosoftCodeAnalysisVersion_3_11)</RoslynApiVersion>
</PropertyGroup>
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AnalyzerRoslynVersion>4.0</AnalyzerRoslynVersion>
<RoslynApiVersion>$(MicrosoftCodeAnalysisVersion_4_0)</RoslynApiVersion>
<DefineConstants>$(DefineConstants);ROSLYN4_0_OR_GREATER</DefineConstants>
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Source generators must target netstandard2.0 which doesn't support nullable reference types. In order
to enable the nullable reference type compiler checks, we also target NetCoreAppToolCurrent. Note that
this doesn't use the live shared framework but an LKG targeting pack instead to avoid layering concerns. -->
<TargetFrameworks>$(NetCoreAppToolCurrent);netstandard2.0</TargetFrameworks>
<AnalyzerRoslynVersion>4.4</AnalyzerRoslynVersion>
<RoslynApiVersion>$(MicrosoftCodeAnalysisVersion_4_4)</RoslynApiVersion>
<DefineConstants>$(DefineConstants);ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER</DefineConstants>
......@@ -17,4 +21,9 @@
<Compile Include="$(CoreLibSharedDir)System\Collections\Generic\ValueListBuilder.Pop.cs" Link="Production\ValueListBuilder.Pop.cs" />
</ItemGroup>
<!-- Don't reference System.Text.Json from the LKG, as shared sources are compiled into this project. -->
<ItemGroup Condition="'$(TargetFramework)' == '$(NetCoreAppToolCurrent)'">
<DefaultReferenceExclusion Include="System.Text.Json" />
</ItemGroup>
</Project>
<Project>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>$(MSBuildThisFileName)</AssemblyName>
<RootNamespace>$(MSBuildThisFileName)</RootNamespace>
<StringResourcesClassName>SR</StringResourcesClassName>
......@@ -24,6 +23,8 @@
<ItemGroup>
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\IsExternalInit.cs" Link="Common\System\Runtime\CompilerServices\IsExternalInit.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\CompilerFeatureRequiredAttribute.cs" Link="Common\System\Runtime\CompilerServices\CompilerFeatureRequiredAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\RequiredMemberAttribute.cs" Link="Common\System\Runtime\CompilerServices\RequiredMemberAttribute.cs" />
<Compile Include="..\Common\JsonCamelCaseNamingPolicy.cs" Link="Common\System\Text\Json\JsonCamelCaseNamingPolicy.cs" />
<Compile Include="..\Common\JsonNamingPolicy.cs" Link="Common\System\Text\Json\JsonNamingPolicy.cs" />
<Compile Include="..\Common\JsonAttribute.cs" Link="Common\System\Text\Json\Serialization\JsonAttribute.cs" />
......
......@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json.Reflection;
using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis;
......@@ -14,10 +13,18 @@ namespace System.Text.Json.SourceGeneration
[DebuggerDisplay("Type={Type}, ClassType={ClassType}")]
internal sealed class TypeGenerationSpec
{
public TypeGenerationSpec(Type type)
{
Type = type;
TypeRef = type.GetCompilableName();
TypeInfoPropertyName = type.GetTypeInfoPropertyName();
IsValueType = type.IsValueType;
}
/// <summary>
/// Fully qualified assembly name, prefixed with "global::", e.g. global::System.Numerics.BigInteger.
/// </summary>
public string TypeRef { get; private set; }
public string TypeRef { get; private init; }
/// <summary>
/// If specified as a root type via <c>JsonSerializableAttribute</c>, specifies the location of the attribute application.
......@@ -42,7 +49,7 @@ internal sealed class TypeGenerationSpec
public bool GenerateSerializationLogic => GenerationModeIsSpecified(JsonSourceGenerationMode.Serialization) && FastPathIsSupported();
public Type Type { get; private set; }
public Type Type { get; private init; }
public ClassType ClassType { get; private set; }
......@@ -50,7 +57,7 @@ internal sealed class TypeGenerationSpec
public bool ImplementsIJsonOnSerializing { get; private set; }
public bool IsPolymorphic { get; private set; }
public bool IsValueType { get; private set; }
public bool IsValueType { get; private init; }
public bool CanBeNull { get; private set; }
......@@ -93,7 +100,7 @@ internal sealed class TypeGenerationSpec
{
get
{
string builderName;
string? builderName;
if (CollectionType == CollectionType.ImmutableDictionary)
{
......@@ -115,7 +122,6 @@ internal sealed class TypeGenerationSpec
public void Initialize(
JsonSourceGenerationMode generationMode,
Type type,
ClassType classType,
JsonNumberHandling? numberHandling,
List<PropertyGenerationSpec>? propertyGenSpecList,
......@@ -136,11 +142,7 @@ internal sealed class TypeGenerationSpec
bool isPolymorphic)
{
GenerationMode = generationMode;
TypeRef = type.GetCompilableName();
TypeInfoPropertyName = type.GetTypeInfoPropertyName();
Type = type;
ClassType = classType;
IsValueType = type.IsValueType;
CanBeNull = !IsValueType || nullableUnderlyingTypeMetadata != null;
IsPolymorphic = isPolymorphic;
NumberHandling = numberHandling;
......@@ -166,6 +168,8 @@ internal sealed class TypeGenerationSpec
[NotNullWhen(true)] out Dictionary<string, PropertyGenerationSpec>? serializableProperties,
out bool castingRequiredForProps)
{
Debug.Assert(PropertyGenSpecList != null);
castingRequiredForProps = false;
serializableProperties = new Dictionary<string, PropertyGenerationSpec>();
Dictionary<string, PropertyGenerationSpec>? ignoredMembers = null;
......@@ -283,6 +287,8 @@ private bool FastPathIsSupported()
return false;
}
Debug.Assert(PropertyGenSpecList != null);
foreach (PropertyGenerationSpec property in PropertyGenSpecList)
{
if (property.TypeGenerationSpec.Type.IsObjectType() ||
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册