-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Conversation
@@ -60,12 +60,21 @@ internal class BuildRequest | |||
} | |||
} | |||
|
|||
#if USES_ANNOTATIONS |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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)]; } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 !
?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #26651 #Resolved
5a49644
to
47d6fa3
Compare
if (!ReadBytes(reader, 8, out byte[] name)) | ||
#endif |
There was a problem hiding this comment.
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!; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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)!; |
There was a problem hiding this comment.
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!; |
There was a problem hiding this comment.
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
Getting some strange error on Ubuntu (details). @jaredpar @agocke Do you have any clue?
|
# 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
637f0ac
to
564515e
Compare
564515e
to
13e999b
Compare
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 |
There was a problem hiding this comment.
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?! |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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!)) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?
I encountered a couple of minor issues so far:
!
fails to suppress warning #26618 (Adding!
fails to suppress warning)@cston @dotnet/roslyn-compiler for review. Thanks