Skip to content

Commit 166abd7

Browse files
committed
Extensions: xml docs
1 parent 9233fa3 commit 166abd7

File tree

5 files changed

+717
-6
lines changed

5 files changed

+717
-6
lines changed

src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ public override Binder VisitXmlNameAttribute(XmlNameAttributeSyntax parent)
12131213
{
12141214
case XmlNameAttributeElementKind.Parameter:
12151215
case XmlNameAttributeElementKind.ParameterReference:
1216-
result = GetParameterNameAttributeValueBinder(memberSyntax, result);
1216+
result = GetParameterNameAttributeValueBinder(memberSyntax, isParamRef: elementKind == XmlNameAttributeElementKind.ParameterReference, nextBinder: result);
12171217
break;
12181218
case XmlNameAttributeElementKind.TypeParameter:
12191219
result = GetTypeParameterNameAttributeValueBinder(memberSyntax, includeContainingSymbols: false, nextBinder: result);
@@ -1234,16 +1234,28 @@ public override Binder VisitXmlNameAttribute(XmlNameAttributeSyntax parent)
12341234
/// We're in a <param> or <paramref> element, so we want a binder that can see
12351235
/// the parameters of the associated member and nothing else.
12361236
/// </summary>
1237-
private Binder GetParameterNameAttributeValueBinder(MemberDeclarationSyntax memberSyntax, Binder nextBinder)
1237+
private Binder GetParameterNameAttributeValueBinder(MemberDeclarationSyntax memberSyntax, bool isParamRef, Binder nextBinder)
12381238
{
12391239
if (memberSyntax is BaseMethodDeclarationSyntax { ParameterList: { ParameterCount: > 0 } } baseMethodDeclSyntax)
12401240
{
12411241
Binder outerBinder = VisitCore(memberSyntax.Parent);
12421242
MethodSymbol method = GetMethodSymbol(baseMethodDeclSyntax, outerBinder);
1243+
1244+
if (isParamRef && method.TryGetInstanceExtensionParameter(out var _))
1245+
{
1246+
nextBinder = new WithExtensionParameterBinder(method.ContainingType, nextBinder);
1247+
}
1248+
12431249
return new WithParametersBinder(method.Parameters, nextBinder);
12441250
}
1245-
1246-
if (memberSyntax is TypeDeclarationSyntax { ParameterList: { ParameterCount: > 0 } } typeDeclaration)
1251+
else if (memberSyntax is ExtensionDeclarationSyntax extensionDeclaration)
1252+
{
1253+
_ = extensionDeclaration.ParameterList;
1254+
Binder outerBinder = VisitCore(memberSyntax);
1255+
SourceNamedTypeSymbol type = ((NamespaceOrTypeSymbol)outerBinder.ContainingMemberOrLambda).GetSourceTypeMember((TypeDeclarationSyntax)memberSyntax);
1256+
return new WithExtensionParameterBinder(type, nextBinder);
1257+
}
1258+
else if (memberSyntax is TypeDeclarationSyntax { ParameterList: { ParameterCount: > 0 } } typeDeclaration)
12471259
{
12481260
_ = typeDeclaration.ParameterList;
12491261
Binder outerBinder = VisitCore(memberSyntax);
@@ -1268,6 +1280,11 @@ private Binder GetParameterNameAttributeValueBinder(MemberDeclarationSyntax memb
12681280

12691281
ImmutableArray<ParameterSymbol> parameters = property.Parameters;
12701282

1283+
if (isParamRef && property.TryGetInstanceExtensionParameter(out var _))
1284+
{
1285+
nextBinder = new WithExtensionParameterBinder(property.ContainingType, nextBinder);
1286+
}
1287+
12711288
// BREAK: Dev11 also allows "value" for readonly properties, but that doesn't
12721289
// make sense and we don't have a symbol.
12731290
if ((object)property.SetMethod != null)
@@ -1278,8 +1295,10 @@ private Binder GetParameterNameAttributeValueBinder(MemberDeclarationSyntax memb
12781295

12791296
if (parameters.Any())
12801297
{
1281-
return new WithParametersBinder(parameters, nextBinder);
1298+
nextBinder = new WithParametersBinder(parameters, nextBinder);
12821299
}
1300+
1301+
return nextBinder;
12831302
}
12841303
else if (memberKind == SyntaxKind.DelegateDeclaration)
12851304
{

src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,29 @@ public override void VisitNamedType(NamedTypeSymbol symbol)
237237
}
238238

239239
#nullable enable
240+
public override void VisitMethod(MethodSymbol symbol)
241+
{
242+
if (symbol is SourceExtensionImplementationMethodSymbol implementation)
243+
{
244+
var symbolForDocComment = implementation.UnderlyingMethod is SourcePropertyAccessorSymbol accessorSymbol
245+
? accessorSymbol.AssociatedSymbol
246+
: implementation.UnderlyingMethod;
247+
248+
if (symbolForDocComment.GetDocumentationCommentXml(preferredCulture: null, _processIncludes, _cancellationToken).IsEmpty())
249+
{
250+
return;
251+
}
252+
253+
WriteLine("<member name=\"{0}\">", symbol.GetDocumentationCommentId());
254+
Indent();
255+
WriteLine("<inheritdoc cref=\"{0}\"/>", symbolForDocComment.GetDocumentationCommentId());
256+
Unindent();
257+
WriteLine("</member>");
258+
return;
259+
}
260+
261+
DefaultVisit(symbol);
262+
}
240263

241264
/// <summary>
242265
/// Compile documentation comments on the symbol and write them to the stream if one is provided.

src/Compilers/CSharp/Portable/DocumentationComments/DocumentationCommentIDVisitor.PartVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public override object VisitNamedType(NamedTypeSymbol symbol, StringBuilder buil
181181
builder.Append('.');
182182
}
183183

184-
builder.Append(symbol.Name);
184+
builder.Append(symbol.IsExtension ? symbol.ExtensionName : symbol.Name);
185185

186186
if (symbol.Arity != 0)
187187
{

src/Compilers/CSharp/Portable/Symbols/Extensions/SourceExtensionImplementationMethodSymbol.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
1111
{
1212
internal sealed class SourceExtensionImplementationMethodSymbol : RewrittenMethodSymbol // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Do we need to implement ISynthesizedMethodBodyImplementationSymbol?
1313
{
14+
private string? lazyDocComment;
15+
1416
public SourceExtensionImplementationMethodSymbol(MethodSymbol sourceMethod)
1517
: base(sourceMethod, TypeMap.Empty, sourceMethod.ContainingType.TypeParameters.Concat(sourceMethod.TypeParameters))
1618
{
@@ -131,6 +133,11 @@ internal override int TryGetOverloadResolutionPriority()
131133
return UnderlyingMethod.TryGetOverloadResolutionPriority();
132134
}
133135

136+
public override string GetDocumentationCommentXml(CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default)
137+
{
138+
return SourceDocumentationCommentUtils.GetAndCacheDocumentationComment(this, expandIncludes, ref lazyDocComment);
139+
}
140+
134141
private sealed class ExtensionMetadataMethodParameterSymbol : RewrittenMethodParameterSymbol
135142
{
136143
public ExtensionMetadataMethodParameterSymbol(SourceExtensionImplementationMethodSymbol containingMethod, ParameterSymbol sourceParameter) :

0 commit comments

Comments
 (0)