-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Extensions: update xml docs to new metadata design #79641
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
Conversation
f78dea1 to
dc61bd5
Compare
dc61bd5 to
e5261d8
Compare
|
@jjonescz @dotnet/roslyn-compiler for review. Thanks |
| throw ExceptionUtilities.Unreachable(); | ||
| } | ||
|
|
||
| internal ImmutableArray<SourceNamedTypeSymbol> GetMatchingExtensions(SourceNamedTypeSymbol extension) |
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.
| ArrayBuilder<SourceNamedTypeSymbol> extensions = sortSourceNamedTypeSymbols(markerMap[markerName]); | ||
| yield return extensions; | ||
|
|
||
| extensions.Free(); |
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 is very fragile, we don't know whether the consumer is done with the builder. Should find other ways to manage builders. Perhaps this method shouldn't allocate new builder (if it is done for sorting, that could be consumer's responsibility), or it should return a builder of builders and the consumer will be responsible to free them once done. #Closed
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.
Alternatively, consumer can pass a delegate that will be executed for each builder and then the builder will be freed.
| get | ||
| { | ||
| Debug.Assert(ExtensionMarkerTypes[0].UnderlyingExtensions[0].ContainingType is not null); | ||
| return ExtensionMarkerTypes[0].UnderlyingExtensions[0].ContainingType!.GetCciAdapter(); |
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.
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.
Yes, because of the array access
| firstExtension = extension; | ||
| } | ||
|
|
||
| if (!TryGetDocumentationCommentNodes(extension, out var maxDocumentationMode, out var foundDocCommentNodes)) |
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 (documentedTypeParameters != null) | ||
| { | ||
| PooledHashSet<string> documentedTypeParameterNames = PooledHashSet<string>.GetInstance(); |
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.
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.
Could you provide details why the switch to hashset of names was reverted?
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.
It caused a regression. I captured the scenario in XmlDoc_16 where we would have spurious WRN_DuplicateTypeParamTag. I'm punting on resolving this for now (added tracking issue to XmlDoc_05)
| Debug.Assert(extension.IsExtension); | ||
| if (firstExtension is null) | ||
| { | ||
| firstExtension = extension; |
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.
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 made this comment because GetMatchingExtensions doesn't explicitly sort the array before returning, but it looks like the array was sorted as part of its creation. It feels confusing though that two APIs return the "same" sequence of types as different collections types.
| if (symbol.IsExtension && (SourceNamedTypeSymbol)symbol.ContainingType is { } containingType) | ||
| { | ||
| ImmutableArray<SourceNamedTypeSymbol> extensions = containingType.GetExtensionGroupingInfo().GetMatchingExtensions((SourceNamedTypeSymbol)symbol); | ||
| appendMergedExtensionBlocks(extensions); |
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.
|
|
||
| foreach (var markerName in markerNames) | ||
| { | ||
| ArrayBuilder<SourceNamedTypeSymbol> extensions = sortSourceNamedTypeSymbols(markerMap[markerName]); |
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.
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.
Also, note that _lazyGroupingTypes already gives grouping types in deterministic, sorted order, and each of them provides ExtensionMarkerTypes in deterministic, sorted order, and each of them has UnderlyingExtensions in the desired sorted order. BTW, GetMatchingExtensions uses them instead.
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.
Thanks. Simplified
It looks like the comment can be removed now. #Closed Refers to: src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs:2707 in e5261d8. [](commit_id = e5261d8, deletion_comment = False) |
| } | ||
|
|
||
| internal override string ExtensionName | ||
| internal override string ExtensionGroupingName |
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.
|
|
||
| var e = comp.GetMember<NamedTypeSymbol>("E"); | ||
|
|
||
| var extensions = e.GetTypeMembers().ToArray(); |
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.
| AssertEx.Equal("T:E.<Extension>$C43E2675C7BBF9284AF22FB8A9BF0280.<Extension>$8048A6C8BE30A622530249B904B537EB.<Marker>$D1693D81A12E8DED4ED68FE22D9E856F", | ||
| nestedExtension.GetDocumentationCommentId()); | ||
|
|
||
| // PROTOTYPE should we be merging these nested extension blocks instead? |
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.
| } | ||
|
|
||
| /// <typeparam name="T2">Description for T2</typeparam> | ||
| extension<T2, U>(C<T2, U> c) |
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.
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.
XmlDoc_05. Note: it was fixed by tracking type parameters by name (it now reports a warning for documenting type parameter twice)
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.
Do we test scenario where this type parameter ins named "T1" (to force merging with the previous extension)?
XmlDoc_05. Note: it was fixed by tracking type parameters by name (it now reports a warning for documenting type parameter twice)
I assume the answer is "No" then. It appears this test is focusing on a different aspect, ErrorCode.WRN_MissingTypeParamTag.
|
Done with review pass (commit 1) #Closed |
It's removed in next PR where I also added explicit test for this scenario/path In reply to: 3137046726 Refers to: src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs:2707 in e5261d8. [](commit_id = e5261d8, deletion_comment = False) |
| } | ||
|
|
||
| internal override string ExtensionGroupingName | ||
| => _underlyingType.ExtensionGroupingName; |
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.
It feels like the concept of grouping and marker name should only be applicable to definitions. Maybe we could avoid implementation here by adjusting callers (symbol display and docID). What do you think? #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 think the implementation is simple enough to not introduce additional complexity on consumer's side.
|
@jjonescz for second review. Thanks |
|
@jcouv It looks like there are legitimate test failures |
| throw ExceptionUtilities.Unreachable(); | ||
| } | ||
|
|
||
| // Given an extension block, returns all the extensions that are grouped together with 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.
| get { throw ExceptionUtilities.Unreachable(); } | ||
| } | ||
|
|
||
| internal override string ExtensionGroupingName |
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.
|
|
||
| private int _nextSourceIncludeElementIndex; | ||
| private HashSet<Location> _inProgressIncludeElementNodes; | ||
| private HashSet<ParameterSymbol> _documentedParameters; |
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.
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.
It's possible, but I'd rather not spend time to track this through now and if we open an issue to look at it later I doubt we'll get to it in MQ. So I prefer to let it be.
|
Done with review pass (commit 2) #Closed |
| } | ||
|
|
||
| return _lazyUncommonProperties.extensionInfo.GroupingTypeSymbol.MetadataName; // PROTOTYPE: is this the right value to return? | ||
| } |
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 the prototype comment still valid? #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.
It's removed in next PR where I also added explicit test for this scenario/path
| return GetCorrespondingMarkerType(extension).UnderlyingExtensions; | ||
| } | ||
|
|
||
| // Returns all the extension blocks but grouped/merged by equivalency (ie. same marker name) |
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 turning this into a doc comment. #Resolved
| { | ||
| get | ||
| { | ||
| Debug.Assert(ExtensionMarkerTypes[0].UnderlyingExtensions[0].ContainingType is not 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.
Consider extracting ExtensionMarkerTypes[0].UnderlyingExtensions[0].ContainingType into a variable and removing the suppression below. #Resolved
| } | ||
| if (_lazyExtensionInfo.LazyExtensionMarkerName is null) | ||
| { | ||
| _lazyExtensionInfo.LazyExtensionMarkerName = "<Marker>$" + RawNameToHashString(ComputeExtensionMarkerRawName()); // PROTOTYPE: Add a constant for this prefix. |
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 wonder whether we should choose shorter metadata prefixes like <E>$ and <M>$ (I'm not sure if even all the special characters are necessary, perhaps keep only the $) to avoid bloating up metadata sizes. #ByDesign
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.
Seems reasonable. Please reply to the email thread I started on the naming convention topic if you want to suggest a change
Is there a similar warning for parameters? If so, perhaps one should be expected in this scenario too. #Resolved Refers to: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs:48213 in 7f20a26. [](commit_id = 7f20a26, deletion_comment = False) |
AlekseyTs
left a comment
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.
LGTM (commit 6)
Docs on extension blocks are attached to the corresponding extension marker type (docID is
<ContainingType>.<GroupingType>.<MarkerType>).Docs on equivalent extensions blocks (ie. same marker name) are merged silently.
Closes #79043 (fixed by new metadata design change, which uses marker names as grouping keys)
Relates to test plan #76130