Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 17 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@
'$(IsPublishedAppTestProject)' != 'true' and
'$(IsTestSupportProject)' != 'true' and
'$(UsingMicrosoftDotNetSharedFrameworkSdk)' != 'true' and
'$(MSBuildProjectExtension)' != '.pkgproj' and
'$(UsingMicrosoftNoTargetsSdk)' != 'true' and
'$(UsingMicrosoftTraversalSdk)' != 'true'">true</IsSourceProject>
</PropertyGroup>
Expand Down
11 changes: 6 additions & 5 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<!-- Keep in sync as required by the Packaging SDK in Arcade. -->
<Description>$(PackageDescription)</Description>
</PropertyGroup>

<ItemDefinitionGroup>
<TargetPathWithTargetPlatformMoniker>
<IsReferenceAssemblyProject>$(IsReferenceAssemblyProject)</IsReferenceAssemblyProject>
Expand Down Expand Up @@ -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'"
ViktorHofer marked this conversation as resolved.
Show resolved Hide resolved
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. -->
Expand Down
4 changes: 2 additions & 2 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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>
Expand Down
3 changes: 2 additions & 1 deletion eng/packaging.targets
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions src/libraries/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<!-- By default, disable implicit framework references for NetCoreAppCurrent libraries. -->
<DisableImplicitFrameworkReferences Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '$(NETCoreAppCurrentVersion)')) and
('$(IsNETCoreAppRef)' == 'true' or '$(IsNETCoreAppSrc)' == 'true')">true</DisableImplicitFrameworkReferences>
('$(IsNETCoreAppRef)' == 'true' or '$(IsNETCoreAppSrc)' == 'true' or '$(IsNETCoreAppAnalyzer)' == 'true')">true</DisableImplicitFrameworkReferences>
<!-- Enable trimming for any source project that's part of the shared framework.
Don't attempt to trim PNSE assemblies which are generated from the reference source. -->
<ILLinkTrimAssembly Condition="'$(ILLinkTrimAssembly)' == '' and
Expand Down Expand Up @@ -95,8 +95,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)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
34 changes: 17 additions & 17 deletions src/libraries/System.Text.Json/System.Text.Json.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
10 changes: 5 additions & 5 deletions src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 22 additions & 6 deletions src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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/>
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down
Loading