From 7b2591d6531af56420092d0ae136911ae507e218 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 20 Oct 2020 11:19:47 -0700 Subject: [PATCH] Enable nullability checks across DllImportGenerator (#213) --- .../GeneratedMarshallingAttribute.cs | 1 - DllImportGenerator/Demo/Demo.csproj | 1 + ...DllImportGenerator.IntegrationTests.csproj | 1 + .../DllImportGenerator.UnitTests.csproj | 1 + .../Verifiers/CSharpAnalyzerVerifier.cs | 4 +-- .../DllImportGenerator/DllImportGenerator.cs | 36 +++++++++---------- .../DllImportGenerator.csproj | 1 + .../DllImportGenerator/DllImportStub.cs | 13 ++++--- .../ManualTypeMarshallingAnalyzer.cs | 2 -- .../ManualTypeMarshallingHelper.cs | 1 - .../Marshalling/MarshallingGenerator.cs | 2 +- .../MarshallingAttributeInfo.cs | 2 -- .../DllImportGenerator/TypePositionInfo.cs | 9 +++-- .../TypeSymbolExtensions.cs | 2 -- 14 files changed, 40 insertions(+), 36 deletions(-) diff --git a/DllImportGenerator/Ancillary.Interop/GeneratedMarshallingAttribute.cs b/DllImportGenerator/Ancillary.Interop/GeneratedMarshallingAttribute.cs index a483c22c1915..11e1b29639fb 100644 --- a/DllImportGenerator/Ancillary.Interop/GeneratedMarshallingAttribute.cs +++ b/DllImportGenerator/Ancillary.Interop/GeneratedMarshallingAttribute.cs @@ -1,4 +1,3 @@ -#nullable enable namespace System.Runtime.InteropServices { diff --git a/DllImportGenerator/Demo/Demo.csproj b/DllImportGenerator/Demo/Demo.csproj index 0ca8c597da9a..65978093bd2d 100644 --- a/DllImportGenerator/Demo/Demo.csproj +++ b/DllImportGenerator/Demo/Demo.csproj @@ -5,6 +5,7 @@ net5.0 true preview + enable diff --git a/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj b/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj index 2932ce632c21..0992142a39e6 100644 --- a/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj +++ b/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj @@ -5,6 +5,7 @@ false Preview true + enable diff --git a/DllImportGenerator/DllImportGenerator.UnitTests/DllImportGenerator.UnitTests.csproj b/DllImportGenerator/DllImportGenerator.UnitTests/DllImportGenerator.UnitTests.csproj index cd384172bce4..e7b9271727f2 100644 --- a/DllImportGenerator/DllImportGenerator.UnitTests/DllImportGenerator.UnitTests.csproj +++ b/DllImportGenerator/DllImportGenerator.UnitTests/DllImportGenerator.UnitTests.csproj @@ -4,6 +4,7 @@ net5.0 false Preview + enable diff --git a/DllImportGenerator/DllImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs b/DllImportGenerator/DllImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs index b6bd0f531648..be1f1f4e7368 100644 --- a/DllImportGenerator/DllImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs +++ b/DllImportGenerator/DllImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs @@ -48,8 +48,8 @@ public Test() ReferenceAssemblies = refAssem; SolutionTransforms.Add((solution, projectId) => { - var project = solution.GetProject(projectId); - var compilationOptions = project.CompilationOptions; + var project = solution.GetProject(projectId)!; + var compilationOptions = project.CompilationOptions!; compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); diff --git a/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs b/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs index 7d7e42eacb0c..1b4588f3fc05 100644 --- a/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs +++ b/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs @@ -49,17 +49,17 @@ public void Execute(GeneratorExecutionContext context) } // Process the method syntax and get its SymbolInfo. - var methodSymbolInfo = sm.GetDeclaredSymbol(methodSyntax, context.CancellationToken); + var methodSymbolInfo = sm.GetDeclaredSymbol(methodSyntax, context.CancellationToken)!; // Process the attributes on the method. DllImportStub.GeneratedDllImportData dllImportData; AttributeSyntax dllImportAttr = this.ProcessAttributes(methodSymbolInfo, context.CancellationToken, out dllImportData); - Debug.Assert(!(dllImportAttr is null) && !(dllImportData is null)); + Debug.Assert((dllImportAttr is not null) && (dllImportData is not null)); // Create the stub. - var dllImportStub = DllImportStub.Create(methodSymbolInfo, dllImportData, context.Compilation, generatorDiagnostics, context.CancellationToken); + var dllImportStub = DllImportStub.Create(methodSymbolInfo, dllImportData!, context.Compilation, generatorDiagnostics, context.CancellationToken); - PrintGeneratedSource(generatedDllImports, methodSyntax, dllImportStub, dllImportAttr); + PrintGeneratedSource(generatedDllImports, methodSyntax, dllImportStub, dllImportAttr!); } Debug.WriteLine(generatedDllImports.ToString()); // [TODO] Find some way to emit this for debugging - logs? @@ -161,7 +161,7 @@ private AttributeSyntax ProcessAttributes( // Found the GeneratedDllImport, but it has an error so report the error. // This is most likely an issue with targeting an incorrect TFM. - if (attrData.AttributeClass.TypeKind == TypeKind.Error) + if (attrData.AttributeClass?.TypeKind is null or TypeKind.Error) { // [TODO] Report GeneratedDllImport has an error - corrupt metadata? throw new InvalidProgramException(); @@ -170,7 +170,7 @@ private AttributeSyntax ProcessAttributes( var newAttributeArgs = new List(); // Populate the DllImport data from the GeneratedDllImportAttribute attribute. - dllImportData.ModuleName = attrData.ConstructorArguments[0].Value.ToString(); + dllImportData.ModuleName = attrData.ConstructorArguments[0].Value!.ToString(); newAttributeArgs.Add(SyntaxFactory.AttributeArgument(SyntaxFactory.LiteralExpression( SyntaxKind.StringLiteralExpression, @@ -179,60 +179,60 @@ private AttributeSyntax ProcessAttributes( // All other data on attribute is defined as NamedArguments. foreach (var namedArg in attrData.NamedArguments) { - ExpressionSyntax expSyntaxMaybe = null; + ExpressionSyntax? expSyntaxMaybe = null; switch (namedArg.Key) { default: Debug.Fail($"An unknown member was found on {GeneratedDllImport}"); continue; case nameof(DllImportStub.GeneratedDllImportData.BestFitMapping): - dllImportData.BestFitMapping = (bool)namedArg.Value.Value; + dllImportData.BestFitMapping = (bool)namedArg.Value.Value!; expSyntaxMaybe = CreateBoolExpressionSyntax(dllImportData.BestFitMapping); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.BestFitMapping; break; case nameof(DllImportStub.GeneratedDllImportData.CallingConvention): - dllImportData.CallingConvention = (CallingConvention)namedArg.Value.Value; + dllImportData.CallingConvention = (CallingConvention)namedArg.Value.Value!; expSyntaxMaybe = CreateEnumExpressionSyntax(dllImportData.CallingConvention); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.CallingConvention; break; case nameof(DllImportStub.GeneratedDllImportData.CharSet): - dllImportData.CharSet = (CharSet)namedArg.Value.Value; + dllImportData.CharSet = (CharSet)namedArg.Value.Value!; expSyntaxMaybe = CreateEnumExpressionSyntax(dllImportData.CharSet); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.CharSet; break; case nameof(DllImportStub.GeneratedDllImportData.EntryPoint): - dllImportData.EntryPoint = (string)namedArg.Value.Value; - expSyntaxMaybe = CreateStringExpressionSyntax(dllImportData.EntryPoint); + dllImportData.EntryPoint = (string)namedArg.Value.Value!; + expSyntaxMaybe = CreateStringExpressionSyntax(dllImportData.EntryPoint!); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.EntryPoint; break; case nameof(DllImportStub.GeneratedDllImportData.ExactSpelling): - dllImportData.ExactSpelling = (bool)namedArg.Value.Value; + dllImportData.ExactSpelling = (bool)namedArg.Value.Value!; expSyntaxMaybe = CreateBoolExpressionSyntax(dllImportData.ExactSpelling); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.ExactSpelling; break; case nameof(DllImportStub.GeneratedDllImportData.PreserveSig): - dllImportData.PreserveSig = (bool)namedArg.Value.Value; + dllImportData.PreserveSig = (bool)namedArg.Value.Value!; expSyntaxMaybe = CreateBoolExpressionSyntax(dllImportData.PreserveSig); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.PreserveSig; break; case nameof(DllImportStub.GeneratedDllImportData.SetLastError): - dllImportData.SetLastError = (bool)namedArg.Value.Value; + dllImportData.SetLastError = (bool)namedArg.Value.Value!; expSyntaxMaybe = CreateBoolExpressionSyntax(dllImportData.SetLastError); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.SetLastError; break; case nameof(DllImportStub.GeneratedDllImportData.ThrowOnUnmappableChar): - dllImportData.ThrowOnUnmappableChar = (bool)namedArg.Value.Value; + dllImportData.ThrowOnUnmappableChar = (bool)namedArg.Value.Value!; expSyntaxMaybe = CreateBoolExpressionSyntax(dllImportData.ThrowOnUnmappableChar); dllImportData.IsUserDefined |= DllImportStub.DllImportMember.ThrowOnUnmappableChar; break; } - Debug.Assert(!(expSyntaxMaybe is null)); + Debug.Assert(expSyntaxMaybe is not null); // Defer the name equals syntax till we know the value means something. If we created // an expression we know the key value was valid. NameEqualsSyntax nameSyntax = SyntaxFactory.NameEquals(namedArg.Key); - newAttributeArgs.Add(SyntaxFactory.AttributeArgument(nameSyntax, null, expSyntaxMaybe)); + newAttributeArgs.Add(SyntaxFactory.AttributeArgument(nameSyntax, null, expSyntaxMaybe!)); } // If the EntryPoint property is not set, we will compute and diff --git a/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj b/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj index 20b90b8c0045..b64ed81b96b4 100644 --- a/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj +++ b/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj @@ -7,6 +7,7 @@ True true Preview + enable Microsoft.Interop diff --git a/DllImportGenerator/DllImportGenerator/DllImportStub.cs b/DllImportGenerator/DllImportGenerator/DllImportStub.cs index 46e35ddff34e..a5295ac41602 100644 --- a/DllImportGenerator/DllImportGenerator/DllImportStub.cs +++ b/DllImportGenerator/DllImportGenerator/DllImportStub.cs @@ -18,11 +18,16 @@ internal class DllImportStub private TypePositionInfo returnTypeInfo; private IEnumerable paramsTypeInfo; +// We don't need the warnings around not setting the various +// non-nullable fields/properties on this type in the constructor +// since we always use a property initializer. +#pragma warning disable 8618 private DllImportStub() { } +#pragma warning restore - public string StubTypeNamespace { get; private set; } + public string? StubTypeNamespace { get; private set; } public IEnumerable StubContainingTypes { get; private set; } @@ -75,7 +80,7 @@ public enum DllImportMember /// public class GeneratedDllImportData { - public string ModuleName { get; set; } + public string ModuleName { get; set; } = null!; /// /// Value set by the user on the original declaration. @@ -88,7 +93,7 @@ public class GeneratedDllImportData public bool BestFitMapping { get; set; } = true; public CallingConvention CallingConvention { get; set; } = CallingConvention.Winapi; public CharSet CharSet { get; set; } = CharSet.Ansi; - public string EntryPoint { get; set; } = null; + public string EntryPoint { get; set; } = null!; public bool ExactSpelling { get; set; } = false; // VB has different and unusual default behavior here. public bool PreserveSig { get; set; } = true; public bool SetLastError { get; set; } = false; @@ -106,7 +111,7 @@ public static DllImportStub Create( token.ThrowIfCancellationRequested(); // Determine the namespace - string stubTypeNamespace = null; + string? stubTypeNamespace = null; if (!(method.ContainingNamespace is null) && !method.ContainingNamespace.IsGlobalNamespace) { diff --git a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingAnalyzer.cs b/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingAnalyzer.cs index 0cc4f2beb5fd..9cb682d1d38c 100644 --- a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingAnalyzer.cs +++ b/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingAnalyzer.cs @@ -5,8 +5,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -#nullable enable - namespace Microsoft.Interop { [DiagnosticAnalyzer(LanguageNames.CSharp)] diff --git a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs b/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs index f309d3127048..665e14a80b85 100644 --- a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs +++ b/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs @@ -1,4 +1,3 @@ -#nullable enable using System.Linq; using Microsoft.CodeAnalysis; diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs b/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs index 8a96624dd281..cbeb703b8b27 100644 --- a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs +++ b/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs @@ -89,7 +89,7 @@ public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext c /// /// [Optional] Specific reason marshalling of the supplied type isn't supported. /// - public string NotSupportedDetails { get; init; } + public string? NotSupportedDetails { get; init; } } internal class MarshallingGenerators diff --git a/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs b/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs index 913de016c7b3..51e1241bb6ac 100644 --- a/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs +++ b/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs @@ -4,8 +4,6 @@ using System.Diagnostics; using System.Runtime.InteropServices; -#nullable enable - namespace Microsoft.Interop { // The following types are modeled to fit with the current prospective spec diff --git a/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs b/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs index 2ef1705dcbeb..61c0cd246def 100644 --- a/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs +++ b/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs @@ -24,12 +24,17 @@ internal sealed class TypePositionInfo public const int UnsetIndex = int.MinValue; public const int ReturnIndex = UnsetIndex + 1; +// We don't need the warnings around not setting the various +// non-nullable fields/properties on this type in the constructor +// since we always use a property initializer. +#pragma warning disable 8618 private TypePositionInfo() { this.ManagedIndex = UnsetIndex; this.NativeIndex = UnsetIndex; this.UnmanagedLCIDConversionArgIndex = UnsetIndex; } +#pragma warning restore public string InstanceIdentifier { get; private set; } public ITypeSymbol ManagedType { get; private set; } @@ -46,7 +51,7 @@ private TypePositionInfo() public int NativeIndex { get; set; } public int UnmanagedLCIDConversionArgIndex { get; private set; } - public MarshallingInfo MarshallingAttributeInfo { get; private set; } + public MarshallingInfo? MarshallingAttributeInfo { get; private set; } public static TypePositionInfo CreateForParameter(IParameterSymbol paramSymbol, DefaultMarshallingInfo defaultInfo, Compilation compilation, GeneratorDiagnostics diagnostics) { @@ -78,7 +83,6 @@ public static TypePositionInfo CreateForType(ITypeSymbol type, IEnumerable attributes, DefaultMarshallingInfo defaultInfo, Compilation compilation, GeneratorDiagnostics diagnostics) { MarshallingInfo? marshallingInfo = null; @@ -276,7 +280,6 @@ static NativeMarshallingAttributeInfo CreateNativeMarshallingInfo(ITypeSymbol ty return null; } } -#nullable restore private static SyntaxKind RefKindToSyntax(RefKind refKind) { diff --git a/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs b/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs index 97e6b5cf1b67..753ffc636ca0 100644 --- a/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs +++ b/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs @@ -9,8 +9,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -#nullable enable - namespace Microsoft.Interop { static class TypeSymbolExtensions