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 nullable for the mapper types and code clean-up #26989

Merged
merged 4 commits into from
Aug 8, 2022

Conversation

ViktorHofer
Copy link
Member

Fixes #25760

I left out the mapper types in my previous changes as I haven't yet looked into them more closely. I just spent several hours drawing a call stack and trying to understand the mapping infrastructure and I fell much more enlightened now 😁.

@ViktorHofer ViktorHofer self-assigned this Aug 4, 2022
@ViktorHofer ViktorHofer requested review from a team and joperezr as code owners August 4, 2022 13:24
@@ -9,17 +9,17 @@ namespace Microsoft.DotNet.ApiCompatibility.Abstractions
/// Class to wrap an Element of T with it's <see cref="MetadataInformation"/>.
/// </summary>
/// <typeparam name="T">The type of the Element that is holded</typeparam>
public class ElementContainer<T> where T : ISymbol
public readonly struct ElementContainer<T> where T : ISymbol
Copy link
Member Author

Choose a reason for hiding this comment

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

Changes in this file are unrelated but are an optimization (using a readonly struct over class reduces run time costs) that I felt isn't worth putting into a separate PR.

/// <summary>
/// Gets the assembly load errors that happened when trying to follow type forwards.
/// </summary>
public IReadOnlyList<IReadOnlyList<CompatDifference>> AssemblyLoadErrors => _assemblyLoadErrors;
Copy link
Member Author

Choose a reason for hiding this comment

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

Moving the AssemblyLoadErrors from the the base ElementMapper type into the AssemblyMapper as that's the only mapper that deals with resolving external assemblies (via type forwards). This reduces the instantiation costs of the other mapper types.

Copy link
Member

Choose a reason for hiding this comment

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

That seems fine by me. One small comment is that I'm not sure I understand why is that relevant in the nullability changes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this isn't related to the nullable reference type feature. This is general code clean-up (same as for the other comments that I left on this PR) that I bundled into this PR as I already touched the files.

Comment on lines +48 to +50
for (int i = 0; i < Right.Length; i++)
{
for (int i = 0; i < Right.Length; i++)
{
AddOrCreateMappers(Right[i], ElementSide.Right, i);
}
AddOrCreateMappers(Right[i], ElementSide.Right, i);
Copy link
Member Author

Choose a reason for hiding this comment

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

Same clean-up as in 7304516. The if/else isn't required here.

Comment on lines +34 to +36
for (int i = 0; i < Right.Length; i++)
{
AddOrCreateMappers(Right[0], ElementSide.Right);
}
else
{
for (int i = 0; i < Right.Length; i++)
{
AddOrCreateMappers(Right[i], ElementSide.Right, i);
}
AddOrCreateMappers(Right[i], ElementSide.Right, i);
Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above. The if/else isn't required here.

Comment on lines +13 to +16
/// <summary>
/// The containg type of this member.
/// </summary>
internal TypeMapper ContainingType { get; }
Copy link
Member Author

Choose a reason for hiding this comment

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

style nit: placing the property before the ctor.

Comment on lines +64 to +68
// Retrieve the right names
string[] rightNames = new string[rightCount];
for (int i = 0; i < rightCount; i++)
{
ElementContainer<IAssemblySymbol> element = right[i];
rightNames[i] = element.MetadataInformation.DisplayString;
mapper.AddElement(element.Element, ElementSide.Right, i);
rightNames[i] = right[i].MetadataInformation.DisplayString;
Copy link
Member Author

Choose a reason for hiding this comment

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

Constructing the rightNames before initializing the AssemblyMapper to avoid instantiating a throw-away ComparingSettings object.

AssemblyMapper mapper = new(GetComparingSettingsCore(leftName, rightName != null ? new[] { rightName } : null));
mapper.AddElement(left, ElementSide.Left);
mapper.AddElement(right, ElementSide.Right);

DifferenceVisitor visitor = new();
visitor.Visit(mapper);
return visitor.DiagnosticCollections.First();
return visitor.DiagnosticCollections[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.

Avoiding Linq as the DiagnosticCollections are now exposed as a IReadOnlyList which allows to index on it.

@joperezr
Copy link
Member

joperezr commented Aug 4, 2022

After this, is there anything left to annotate or is this it?

@@ -38,7 +37,7 @@ public class ApiComparer : IApiComparer

DifferenceVisitor visitor = new();
visitor.Visit(mapper);
return visitor.DiagnosticCollections.First();
return visitor.DiagnosticCollections[0];
Copy link
Member

Choose a reason for hiding this comment

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

I know this is not new from your work, but do we have to check if this is null? or if the size of the DiagnosticCollection has at least 1 elemnt?

Copy link
Member Author

@ViktorHofer ViktorHofer Aug 5, 2022

Choose a reason for hiding this comment

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

The size of the DiagnosticCollection is governed by the rightCount ctor parameterof the DifferenceVisitor type and that value defaults to 1:

_diagnostics = new HashSet<CompatDifference>[rightCount];

Also, the individual values in the collection are already initialized to an empty HashSet<CompatDifference>, so this could never be null.

@ViktorHofer
Copy link
Member Author

After this, is there anything left to annotate or is this it?

The underlying issue will get closed when this gets merged. All the shipping code under src/ApiCompat now use the nullable reference type compiler feature (except for the underlying msbuild task infrastructure that comes via the sdk). Also, the feature switch is already enabled for all product code libraries:

@ViktorHofer ViktorHofer changed the title Enable nullable for the mapper types Enable nullable for the mapper types and code clean-up Aug 5, 2022
@ViktorHofer ViktorHofer merged commit baeed26 into dotnet:main Aug 8, 2022
@ViktorHofer ViktorHofer deleted the FinishNullable branch August 8, 2022 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ApiCompat] Enable nullable reference types
3 participants