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

Enable nullability checks across DllImportGenerator #213

Merged
merged 3 commits into from
Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#nullable enable

namespace System.Runtime.InteropServices
{
Expand Down
1 change: 1 addition & 0 deletions DllImportGenerator/Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<TargetFramework>net5.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>

<!-- Indicate to the compiler to output generated files to disk. Source addded
by the DllImportGenerator can be found in the intermediate directory. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
36 changes: 18 additions & 18 deletions DllImportGenerator/DllImportGenerator/DllImportGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
// [TODO] Report GeneratedDllImport has an error - corrupt metadata?
throw new InvalidProgramException();
Expand All @@ -170,7 +170,7 @@ private AttributeSyntax ProcessAttributes(
var newAttributeArgs = new List<AttributeArgumentSyntax>();

// 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,
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>Preview</LangVersion>
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.Interop</RootNamespace>

<!-- Uncomment to generate stub code that simply forwards parameters to p/invoke (i.e. no marshalling) -->
Expand Down
13 changes: 9 additions & 4 deletions DllImportGenerator/DllImportGenerator/DllImportStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@ internal class DllImportStub
private TypePositionInfo returnTypeInfo;
private IEnumerable<TypePositionInfo> 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<TypeDeclarationSyntax> StubContainingTypes { get; private set; }

Expand Down Expand Up @@ -75,7 +80,7 @@ public enum DllImportMember
/// </remarks>
public class GeneratedDllImportData
{
public string ModuleName { get; set; }
public string ModuleName { get; set; } = null!;

/// <summary>
/// Value set by the user on the original declaration.
Expand All @@ -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;
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

#nullable enable

namespace Microsoft.Interop
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#nullable enable

using System.Linq;
using Microsoft.CodeAnalysis;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext c
/// <summary>
/// [Optional] Specific reason marshalling of the supplied type isn't supported.
/// </summary>
public string NotSupportedDetails { get; init; }
public string? NotSupportedDetails { get; init; }
}

internal class MarshallingGenerators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions DllImportGenerator/DllImportGenerator/TypePositionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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)
{
Expand Down Expand Up @@ -78,7 +83,6 @@ public static TypePositionInfo CreateForType(ITypeSymbol type, IEnumerable<Attri
return typeInfo;
}

#nullable enable
private static MarshallingInfo? GetMarshallingInfo(ITypeSymbol type, IEnumerable<AttributeData> attributes, DefaultMarshallingInfo defaultInfo, Compilation compilation, GeneratorDiagnostics diagnostics)
{
MarshallingInfo? marshallingInfo = null;
Expand Down Expand Up @@ -276,7 +280,6 @@ static NativeMarshallingAttributeInfo CreateNativeMarshallingInfo(ITypeSymbol ty
return null;
}
}
#nullable restore

private static SyntaxKind RefKindToSyntax(RefKind refKind)
{
Expand Down
2 changes: 0 additions & 2 deletions DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

#nullable enable

namespace Microsoft.Interop
{
static class TypeSymbolExtensions
Expand Down