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 annotations to MSBuildTask project #26622

Closed
wants to merge 2 commits into from

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented May 4, 2018

I encountered a couple of minor issues so far:

@cston @dotnet/roslyn-compiler for review. Thanks

@jcouv jcouv added this to the 16.0 milestone May 4, 2018
@jcouv jcouv self-assigned this May 4, 2018
@jcouv jcouv requested review from a team as code owners May 4, 2018 02:36
@@ -60,12 +60,21 @@ internal class BuildRequest
}
}

#if USES_ANNOTATIONS
Copy link
Member

@sharwell sharwell May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ If this is in a branch anyway, why have the preprocessor like this? It makes it hard to see the true impact 😦

Edit: Probably a linked file and nullable reference types is only enabled in one of the locations. #Resolved

Copy link
Member Author

@jcouv jcouv May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. I'm setting LangVersion in MSBuildTask first, then other projects will follow. #Resolved

@@ -724,7 +726,7 @@ protected override bool CallHostObjectToExecute()

ICscHostObject cscHostObject = HostObject as ICscHostObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 An InvalidCastException is probably clearer than a NullReferenceException. I believe the following resolves this without requiring the non-null assertion operator.

ICscHostObject cscHostObject = (ICscHostObject)HostObject;

@@ -39,25 +39,25 @@ public ManagedCompiler()
#region Properties

// Please keep these alphabetized.
public string[] AdditionalLibPaths
public string[]? AdditionalLibPaths
{
set { _store[nameof(AdditionalLibPaths)] = value; }
get { return (string[])_store[nameof(AdditionalLibPaths)]; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 This appears to a bug/limitation somewhere. Casting to array types is not catching the issue the same way casting to string below was.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, I remember this is by-design. The cast to (string) doesn't change anything. On the other hand, the cast to (string?) affects the declared nullability of the expression (so var x = (string?)y; gives var a string? type).

@cston to confirm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it allow casting a nullable object to a non-nullable type without !?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A warning should be reported. With the current features/NullableReferenceTypes, the following generates warning CS8600: Converting null literal or possible null value to non-nullable type:

    Dictionary<string, object?> _store = new Dictionary<string, object?>();
    string[]? AdditionalLibPaths
    {
        get { return (string[])_store[nameof(AdditionalLibPaths)]; }
    }

{
set
{
if (UsedCommandLineTool)
{
NormalizePaths(value);
NormalizePaths(value!); // PROTOTYPE(NullableDogfood): value set should be non-null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 I believe this is going to be a common request. Technically the situation occurs many times in this file but this is the only one that catches it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracked by #26621

@@ -939,7 +942,7 @@ private static bool ListHasNoDuplicateItems(ITaskItem[] itemList, string paramet
foreach (ITaskItem item in itemList)
{
string key;
string disambiguatingMetadataValue = null;
string? disambiguatingMetadataValue = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Related to #23281

@@ -24,6 +24,8 @@ public sealed class MapSourceRoots : Task
{
public MapSourceRoots()
{
SourceRoots = null!; // PROTOTYPE(NullableDogfood): Required by MSBuild
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required by MSBuild

📝 Saw this a few times; wasn't quite sure what it means

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SourceRoots property has an attribute [Required] (from MSBuild). It means that MSBuild will check this for us and we can assume that it is already initialized.
The constructor however doesn't know that.

@@ -56,7 +56,7 @@ public RCWForCurrentContext(T rcw)
else
{
_shouldReleaseRCW = true;
_rcwForCurrentCtx = objInCurrentCtx as T;
_rcwForCurrentCtx = (objInCurrentCtx as T)!; // PROTOTYPE(NullableDogfood): class? constraint not yet implemented
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Why not (T)objInCurrentCtx?

if (string.IsNullOrEmpty(path))
{
return path;
}

var c = path[path.Length - 1];
var c = path![path!.Length - 1];
Copy link
Member

@sharwell sharwell May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Isn't the following sufficient?

path[path!.Length - 1]
``` #Resolved

Copy link
Member Author

@jcouv jcouv May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current semantics of ! is to suppress conversion and assignment warnings, but it does not affect the state of the expression it is applied to.

Update: Looking back at LDM notes, ! also changes the top-level nullability of the value returned by the expression. #Resolved

if (c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar)
{
path = path.Substring(0, path.Length - 1);
path = path!.Substring(0, path!.Length - 1);
Copy link
Member

@sharwell sharwell May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Is there a reason ! doesn't propagate in data flow analysis? #Resolved

Copy link
Member Author

@jcouv jcouv May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember the rationale. #Resolved

{
if (methodInfo == null)
{
#if USES_ANNOTATIONS
// PROTOTYPE(NullableDogfood): We will fix with System.Delegate constraint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Isn't this constraint already enabled in this branch due to the use of C# 8.0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler with nullable implementation is based off 15.6 at the moment. System.Delegate was implemented in 15.7.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is the latest build of features/NullableReferenceTypes, it should include dev15.7.x.

@@ -88,7 +104,16 @@ public static T FindItem<T>(IEnumerable<T> collection, params Type[] paramTypes)
}
}

// PROTOTYPE(NullableDogfood): T is constrained to a specific class
// PROTOTYPE(NullableDogfood): ! did not suppress the warning
// https://github.com/dotnet/roslyn/issues/26618
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindItem<T> should be declared to return T?.

@@ -113,11 +117,18 @@ public static void Log(string message)
string output = prefix + message + "\r\n";
byte[] bytes = Encoding.UTF8.GetBytes(output);

// PROTOTYPE(NullableDogfood): There should be no warning on de-referencing s_loggingStream since checked above
Copy link
Member

@cston cston May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, there should be no warning dereferencing the field. We should track static fields and properties. Please log a bug. #Resolved

Copy link
Member Author

@jcouv jcouv May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #26651 #Resolved

@jcouv jcouv force-pushed the nullable-dogfood branch 2 times, most recently from 5a49644 to 47d6fa3 Compare May 5, 2018 02:40
if (!ReadBytes(reader, 8, out byte[] name))
#endif
Copy link
Member

@cston cston May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using byte[] name for ReadBytes and move the annotation comment there. #Resolved

_rcwForCurrentCtx = null;
// PROTOTYPE(NullableDogfood): T should be constrained to class?
// 1>RCWForCurrentContext.cs(119,37,119,41): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
_rcwForCurrentCtx = null!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_rcwForCurrentCtx should be T?.

return default;
#endif
Copy link
Member

@cston cston May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use T? and class constraint?

static T? InvokeConstructor<T>(this ConstructorInfo? constructorInfo, params object[]? args)
    where T : class

@@ -118,8 +149,13 @@ internal sealed class BuildServerConnection
var clientDir = buildPaths.ClientDirectory;
var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess;
var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
#if USES_ANNOTATIONS
Task<NamedPipeClientStream>? pipeTask = null;
Copy link
Member

@cston cston May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Task<NamedPipeClientStream?>? pipeTask = null; #Resolved

@@ -162,7 +198,12 @@ internal sealed class BuildServerConnection

if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
{
#if USES_ANNOTATIONS
// PROTOTYPE(NullableDogfood): Workaround async issue
pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken)!;
Copy link
Member

@cston cston May 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ! needed here? #Pending

@@ -350,7 +398,12 @@ internal sealed class BuildServerConnection
catch (Exception e) when (!(e is TaskCanceledException || e is OperationCanceledException))
{
LogException(e, "Exception while connecting to process");
#if USES_ANNOTATIONS
// PROTOTYPE(NullableDogfood): https://github.com/dotnet/roslyn/issues/26614 There should be no need for !
return null!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#pragma warning disable 8625
        return null;
#pragma warning restore 8625

@jcouv
Copy link
Member Author

jcouv commented May 9, 2018

Getting some strange error on Ubuntu (details). @jaredpar @agocke Do you have any clue?

20:32:59 /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Tools/dotnet/sdk/2.1.300-preview2-008324/Sdks/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets(198,5): error : Could not find a part of the path '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/Dlls/MSBuildTask/netcoreapp2.0/publish/runtimes'. ~~[/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/src/NuGet/NuGetProjectPackUtil.csproj]

20:32:46   csi -> /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/Exes/csi/net46/csi.exe
20:32:47   Toolset -> /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/Exes/Toolset/Toolset_DoNotUse.exe
20:32:47   VBCSCompilerTests -> /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/UnitTests/VBCSCompilerTests/netcoreapp2.0/Roslyn.Compilers.CompilerServer.UnitTests.dll
20:32:47 
20:32:47 Build succeeded.
20:32:47     0 Warning(s)
20:32:47     0 Error(s)
20:32:47 
20:32:47 Time Elapsed 00:02:38.85
20:32:48 /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/src/NuGet /mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest
20:32:48 Packing PreRelease
20:32:50   Successfully created package '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/NuGet/PreRelease/Microsoft.CodeAnalysis.CSharp.2.9.0-dev.nupkg'.
20:32:52   Successfully created package '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/NuGet/PreRelease/Microsoft.CodeAnalysis.Compilers.2.9.0-dev.nupkg'.
20:32:55   Successfully created package '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/NuGet/PreRelease/Microsoft.CodeAnalysis.VisualBasic.2.9.0-dev.nupkg'.
20:32:57   Successfully created package '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/NuGet/PreRelease/Microsoft.CodeAnalysis.Common.2.9.0-dev.nupkg'.
20:32:59 
/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Tools/dotnet/sdk/2.1.300-preview2-008324/Sdks/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets(198,5): error : Could not find a part of the path '/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/Binaries/Debug/Dlls/MSBuildTask/netcoreapp2.0/publish/runtimes'. ~~[/mnt/j/workspace/dotnet_roslyn/features_NullableDogfood/ubuntu_16_debug_prtest/src/NuGet/NuGetProjectPackUtil.csproj]

@jcouv jcouv added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label May 9, 2018
# The first commit's message is:
Add annotations to MSBuildTask project

# The 2nd commit message will be skipped:

#	Fix more annotations after updating the toolset package

# The 3rd commit message will be skipped:

#	Address PR feedback from Chuck and Sam

# The 4th commit message will be skipped:

#	Address PR feedback from Chuck
@jcouv jcouv force-pushed the nullable-dogfood branch 2 times, most recently from 637f0ac to 564515e Compare August 14, 2018 22:17
@jcouv jcouv removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Aug 15, 2018
@jcouv
Copy link
Member Author

jcouv commented Aug 15, 2018

Refreshed this PR with latest nullable toolset.

@@ -9,4 +9,10 @@ public NonNullTypesAttribute(bool b = true)
{
}
}

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
internal class NotNullWhenTrueAttribute : Attribute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotNullWhenTrueAttribute [](start = 19, length = 24)

Consider moving to a separate file.

@@ -556,8 +557,9 @@ private bool InitializeHostCompiler(ICscHostObject cscHostObject)
}
}

// PROTOTYPE(NullableDogfood): Why does flow analysis think cscHostObject might be null here?!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does flow analysis think cscHostObject might be null here?! [](start = 47, length = 63)

Please reference bug #.

@@ -187,7 +187,8 @@ public ITaskItem Source

protected sealed override bool IsManagedTool => !HasToolBeenOverridden;

protected sealed override string PathToManagedTool => Utilities.GenerateFullPathToTool(ToolName);
// PROTOTYPE(NullableDogfood): Need to follow-up, possible compiler bug
Copy link
Member

@cston cston Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to follow-up, possible compiler bug [](start = 39, length = 40)

GenerateFullPathToTool() returns string?. Same comment for instances in other files.

{
if (string.IsNullOrEmpty(features))
{
return;
}

foreach (var feature in CompilerOptionParseUtilities.ParseFeatureFromMSBuild(features))
foreach (var feature in CompilerOptionParseUtilities.ParseFeatureFromMSBuild(features!))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

! [](start = 97, length = 1)

Is this still needed?

{
return s_empty;
}

// PROTOTYPE(NullableDogfood): Need annotation on Guid constructor (throws on null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throws on null [](start = 80, length = 14)

Just [NonNullTypes] Guid(string) correct?

@@ -1094,10 +1096,10 @@ protected override bool CallHostObjectToExecute()
{
Debug.Assert(this.HostObject != null, "We should not be here if the host object has not been set.");

IVbcHostObject vbcHostObject = this.HostObject as IVbcHostObject;
IVbcHostObject vbcHostObject = (IVbcHostObject)this.HostObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(IVbcHostObject)this.HostObject [](start = 43, length = 31)

Is there a reason to use explicit cast rather than as? If so, the asserts below no longer apply.

@@ -61,7 +77,11 @@ public static Type GetTypeFromEither(ref Type lazyType, string contractName, str
return (lazyType == Missing) ? null : lazyType;
}

#if USES_ANNOTATIONS
public static T? FindItem<T>(IEnumerable<T> collection, params Type[] paramTypes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T? [](start = 22, length = 2)

T

@@ -111,26 +144,37 @@ public static T CreateDelegate<T>(this MethodInfo methodInfo)
return (T)(object)methodInfo.CreateDelegate(typeof(T));
}

#if USES_ANNOTATIONS
public static T? InvokeConstructor<T>(this ConstructorInfo? constructorInfo, params object[]? args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T? [](start = 22, length = 2)

T

{
ClientDirectory = clientDir;
ClientDirectory = clientDir ?? string.Empty;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string.Empty [](start = 43, length = 12)

Is this a change in behavior?

@jcouv jcouv added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Sep 11, 2018
@jinujoseph jinujoseph modified the milestones: 16.0, 16.3 Jun 9, 2019
@jcouv jcouv modified the milestones: 16.3, 16.4 Sep 6, 2019
@jinujoseph jinujoseph removed this from the 16.4 milestone Dec 11, 2019
@jcouv jcouv closed this Mar 20, 2020
@jcouv jcouv deleted the nullable-dogfood branch March 20, 2020 02:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers New Language Feature - Nullable Reference Types Nullable Reference Types PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants