Skip to content

Add records support to XmlDocCommentCompletion and ChangeSignature#53052

Merged
CyrusNajmabadi merged 22 commits intodotnet:mainfrom
Youssef1313:records-xml-doc-ide
Jul 12, 2021
Merged

Add records support to XmlDocCommentCompletion and ChangeSignature#53052
CyrusNajmabadi merged 22 commits intodotnet:mainfrom
Youssef1313:records-xml-doc-ide

Conversation

@Youssef1313
Copy link
Member

@Youssef1313 Youssef1313 commented Apr 30, 2021

The change signature part is crashing. The assertion failure is far down to the compiler layer. I wasn't able to figure out how to fix that. Tagging @allisonchou for help here since the issue was assigned to you. Figured out the reason. It's actually an existing bug (see #53089).

Fixes #44558
Fixes #52738

TODOs

@Youssef1313 Youssef1313 requested a review from a team as a code owner April 30, 2021 12:48
@ghost ghost added the Area-IDE label Apr 30, 2021
Comment on lines +378 to +390
const int RecordDeclarationRawKind = 9063;

// A bit hacky to determine the parameters of primary constructor associated with a given record.
// TODO: record structs.
var primaryConstructor = recordSymbol.InstanceConstructors.FirstOrDefault(
c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax()?.RawKind == RecordDeclarationRawKind);

if (primaryConstructor is null)
{
return ImmutableArray<IParameterSymbol>.Empty;
}

return primaryConstructor.Parameters;
Copy link
Member Author

@Youssef1313 Youssef1313 Apr 30, 2021

Choose a reason for hiding this comment

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

Having primary constructor with AssociatedSymbol equals to the record symbol would save this ugly workaround 😄

i.e, Be able to re-write it as recordSymbol.InstanceConstructors.FirstOrDefault(c => recordSymbol.Equals(c.AssociatedSymbol)

@jcouv @jaredpar Is this something you want to do in the compiler side?

Edit: tracked by 53092.

@Youssef1313
Copy link
Member Author

CI is stuck:

image

Closing and reopening to retrigger run.

@Youssef1313 Youssef1313 reopened this Apr 30, 2021
@Youssef1313
Copy link
Member Author

Closing and reopening:

C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error : System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error). [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error :    at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error :    at Microsoft.DotNet.Helix.Sdk.CreateTestsForWorkItems.<>c__DisplayClass5_0.<<AttachResultFileToTestResultAsync>b__0>d.MoveNext() in /_/src/Microsoft.DotNet.Helix/Sdk/CreateFailedTestsForFailedWorkItems.cs:line 73 [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error : --- End of stack trace from previous location --- [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error :    at Microsoft.DotNet.Helix.AzureDevOps.AzureDevOpsTask.<>c__DisplayClass13_0.<<RetryAsync>b__0>d.MoveNext() in /_/src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs:line 91 [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error : --- End of stack trace from previous location --- [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error :    at Microsoft.DotNet.Helix.AzureDevOps.AzureDevOpsTask.RetryAsync[T](Func`1 function, Action`1 logRetry, Func`2 isRetryable, CancellationToken cancellationToken) in /_/src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs:line 206 [D:\a\1\s\helix-tmp.csproj]
C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error :    at Microsoft.DotNet.Helix.AzureDevOps.AzureDevOpsTask.RetryAsync(Func`1 function) in /_/src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs:line 86 [D:\a\1\s\helix-tmp.csproj]

@Youssef1313 Youssef1313 reopened this Apr 30, 2021
@Youssef1313 Youssef1313 reopened this Apr 30, 2021
@jinujoseph jinujoseph added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label Apr 30, 2021
@Youssef1313
Copy link
Member Author

C:\Users\VssAdministrator\.nuget\packages\microsoft.dotnet.helix.sdk\6.0.0-beta.21167.3\tools\azure-pipelines\AzurePipelines.MultiQueue.targets(30,5): error : System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error). [D:\a\1\s\helix-tmp.csproj]

Is this a known issue? Re-run CI for the third time with the same error.

@Youssef1313 Youssef1313 closed this May 1, 2021
@Youssef1313 Youssef1313 reopened this May 1, 2021
SyntaxKind.ParenthesizedLambdaExpression,
SyntaxKind.LocalFunctionStatement);
SyntaxKind.LocalFunctionStatement,
// TODO: Record structs
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to create + link a work item here so we can track adding record struct support in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

@allisonchou It should fall into the existing test plan issue for record structs (#51199). Tagging @jcouv to edit the issue

Copy link
Contributor

Choose a reason for hiding this comment

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

we have record structs now right? so can we just add that in this PR?

// A bit hacky to determine the parameters of primary constructor associated with a given record.
// TODO: record structs.
const int RecordDeclarationRawKind = 9063;
var potentialPrimaryCtor = typeSymbol.InstanceConstructors.FirstOrDefault(
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'm a little worried about hardcoding the raw kind here. I almost think we should wait on merging until we have a proper workaround that doesn't involve hardcoding. @CyrusNajmabadi do you have any thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think #53092 may not be very soon 😕

Copy link
Contributor

Choose a reason for hiding this comment

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

we're in an abstract type, just provide a helper that C# implements, going back to source to answer this.

}

// TODO: Record structs
if (updatedNode.IsKind(SyntaxKind.RecordDeclaration, out RecordDeclarationSyntax? record) && record.ParameterList is not null)
Copy link
Contributor

Choose a reason for hiding this comment

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

just don't do a kind check, and do a syntax-check, and you'll be all good here.

Suggested change
if (updatedNode.IsKind(SyntaxKind.RecordDeclaration, out RecordDeclarationSyntax? record) && record.ParameterList is not null)
if (updatedNode is RecordDeclarationSyntax { ParameterList: not null })

Copy link
Member Author

Choose a reason for hiding this comment

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

image

@CyrusNajmabadi Nullable analysis doesn't seem to handle patterns correctly.

@Youssef1313
Copy link
Member Author

Pinging @CyrusNajmabadi and @allisonchou for review.

Copy link
Contributor

@allisonchou allisonchou left a comment

Choose a reason for hiding this comment

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

Looking really good! Just have a few small comments/questions.

Copy link
Contributor

@allisonchou allisonchou left a comment

Choose a reason for hiding this comment

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

Thanks! This LGTM. 😄

@allisonchou
Copy link
Contributor

@Youssef1313 It looks like there's some check failures, could you take a look?

@Youssef1313
Copy link
Member Author

@CyrusNajmabadi Can you review please? Thanks!

// if GetParameters extension method gets updated to handle records, we need to test EVERY usage
// of the extension method and make sure the change is applicable to all these usages.
var primaryConstructor = recordSymbol.InstanceConstructors.FirstOrDefault(
c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() is RecordDeclarationSyntax);
Copy link
Contributor

Choose a reason for hiding this comment

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

consider extracting helper for this (you do the same work higher up).

// if GetParameters extension method gets updated to handle records, we need to test EVERY usage
// of the extension method and make sure the change is applicable to all these usages.
var primaryConstructor = recordSymbol.InstanceConstructors.FirstOrDefault(
c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() is RecordDeclarationSyntax);
Copy link
Contributor

Choose a reason for hiding this comment

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

used again. consider an extension now.

Comment on lines +135 to +141
else if (typeSymbol.IsRecord)
{
if (TryGetRecordPrimaryConstructor(typeSymbol, out var primaryConstructor))
{
symbol = primaryConstructor;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
else if (typeSymbol.IsRecord)
{
if (TryGetRecordPrimaryConstructor(typeSymbol, out var primaryConstructor))
{
symbol = primaryConstructor;
}
}
else if (typeSymbol.IsRecord && TryGetRecordPrimaryConstructor(typeSymbol, out var primaryConstructor))
{
symbol = primaryConstructor;
}

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

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

lgtm. let me know if you want to add the support for record structs.

var declaredParameters = declarationSymbol.GetParameters();
if (declarationSymbol is INamedTypeSymbol { IsRecord: true } recordSymbol)
if (declarationSymbol is INamedTypeSymbol { IsRecord: true } recordSymbol &&
recordSymbol.TryGetRecordPrimaryConstructor(out var primaryConstructor))
Copy link
Contributor

Choose a reason for hiding this comment

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

You could move the IsRecord check into TryGetPrimaryConstructor

@CyrusNajmabadi
Copy link
Contributor

Thanks!

@CyrusNajmabadi CyrusNajmabadi merged commit 0049504 into dotnet:main Jul 12, 2021
@ghost ghost added this to the Next milestone Jul 12, 2021
@Youssef1313 Youssef1313 deleted the records-xml-doc-ide branch July 12, 2021 02:27
@allisonchou allisonchou modified the milestones: Next, 17.0.P3 Jul 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make sure XmlDocCommentCompletionProvider works with records ChangeSignature: should trigger in positional records

4 participants