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

STJ: Avoid duplicate initialization of required or init-only properties #97726

Merged
merged 12 commits into from
Feb 5, 2024

Conversation

manandre
Copy link
Contributor

Fixes #97621

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Jan 30, 2024
@ghost
Copy link

ghost commented Jan 30, 2024

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #97621

Author: manandre
Assignees: -
Labels:

area-System.Text.Json

Milestone: -

Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

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

There's a test suite in the repo call PropertyVisibilityTests. As part of this change, would it be possible to evaluate the test coverage for shadowed properties (i.e. properties with the new keyword?)

@manandre
Copy link
Contributor Author

There's a test suite in the repo call PropertyVisibilityTests. As part of this change, would it be possible to evaluate the test coverage for shadowed properties (i.e. properties with the new keyword?)

Some tests around shadowed properties already exist but do not cover combination with required and init-only properties, what should be addressed by this PR.

@@ -891,7 +891,9 @@ private TypeGenerationSpec ParseTypeGenerationSpec(in TypeToGenerate typeToGener
// property is static or an indexer
propertyInfo.IsStatic || propertyInfo.Parameters.Length > 0 ||
// It is overridden by a derived property
PropertyIsOverriddenAndIgnored(propertyInfo, state.IgnoredMembers))
PropertyIsOverriddenAndIgnored(propertyInfo, state.IgnoredMembers) ||
Copy link
Member

@eiriktsarpalis eiriktsarpalis Feb 2, 2024

Choose a reason for hiding this comment

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

There's an equivalent implementation in the reflection resolver:

PropertyIsOverriddenAndIgnored(propertyInfo, state.IgnoredProperties))

Should this be updated as well? Do we know the tests are not failing in that case as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, we should keep both implementations aligned. For reflection flow, the deduplication is done at one place for both get and set operations, whereas for the source generation flow the fast-path and initializers deduplication logic were split. With this PR it is handled at the same place for all flows.

Copy link
Member

Choose a reason for hiding this comment

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

Taking a closer look at the implementation -- this method ultimately calls into the AddPropertyWithConflictResolution method which handles conflict resolution (including shadowed properties):

// Is the current property hidden by the previously cached property
// (with `new` keyword, or by overriding)?
memberInfo.IsOverriddenOrShadowedBy(otherSymbol) ||

My impression is that the bug is caused by a missed case in that logic, so it seems to me that it's this particular logic that should be debugged.

If you don't know how to debug source generator code, the easiest way to do that is by adding a unit test in System.Text.Json.SourceGeneration.Roslyn*.Unit.Tests and debugging them.

@eiriktsarpalis
Copy link
Member

eiriktsarpalis commented Feb 5, 2024

@manandre I just pushed changes to the branch that moves the deduplication logic back to the member initializer parser method. On closer examination of the parser logic, I was reminded that no such deduplication should be happening in the property parsing logic (code for shadowed members must be generated for use by the metadata-based serializer). At the same time, property-based deduplication uses the JSON name of the property (configurable via JsonPropertyNameAttribute and property naming policies) whereas this deduplication must happen exclusively on the basis of the .NET member name, so a dedicated deduplication loop made sense.

@manandre
Copy link
Contributor Author

manandre commented Feb 5, 2024

@eiriktsarpalis What do we do for the metadata flow then? I had changed it to keep alignment with source generation flow...

@eiriktsarpalis
Copy link
Member

Good catch, I've reverted the changes.

…neration.Unit.Tests/JsonSourceGeneratorTests.cs
…neration.Unit.Tests/JsonSourceGeneratorTests.cs
Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

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

Thank you @manandre !

@eiriktsarpalis eiriktsarpalis merged commit 8ac26af into dotnet:main Feb 5, 2024
108 of 111 checks passed
@manandre manandre deleted the stj-duplicate-required-init branch February 5, 2024 22:59
@github-actions github-actions bot locked and limited conversation to collaborators Mar 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Source generator in System.Text.Json does not handle shadowed members correctly
2 participants