Skip to content

Commit 4f9014f

Browse files
Show the type parameter list on generic dynamic member tooltips
A dynamic invocation with explicit type arguments (a.Method<int>()) synthesized a non-generic fake method, so the hover showed Method(...) without the generic list. Give the fake a matching set of conventionally named type parameters (T, T2, ...) and specialize it with the actual arguments, as a real generic call produces a SpecializedMethod, so the hover shows the method's generic parameters. Assisted-by: Claude:claude-fable-5:Claude Code
1 parent 4ff11dd commit 4f9014f

1 file changed

Lines changed: 12 additions & 3 deletions

File tree

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4386,7 +4386,7 @@ protected internal override TranslatedExpression VisitDynamicInvokeMemberInstruc
43864386
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
43874387
return new InvocationExpression(targetExpr, arguments.Select(a => a.Expression))
43884388
.WithILInstruction(inst)
4389-
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Invocation, arguments.Select(a => a.ResolveResult).ToArray(), symbol: CreateDynamicInvokeMemberSymbol(inst.Name, inst.ArgumentInfo[0], inst.ArgumentInfo.Skip(1).ToArray())));
4389+
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Invocation, arguments.Select(a => a.ResolveResult).ToArray(), symbol: CreateDynamicInvokeMemberSymbol(inst.Name, inst.ArgumentInfo[0], inst.ArgumentInfo.Skip(1).ToArray(), inst.TypeArguments)));
43904390
}
43914391

43924392
protected internal override TranslatedExpression VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst, TranslationContext context)
@@ -4461,7 +4461,7 @@ IMember CreateDynamicMemberSymbol(string name, CSharpArgumentInfo targetInfo)
44614461
/// typed by <see cref="DynamicArgumentType"/>, so the member reference carries a navigable symbol /
44624462
/// hover tooltip.
44634463
/// </summary>
4464-
IMember CreateDynamicInvokeMemberSymbol(string name, CSharpArgumentInfo targetInfo, IReadOnlyList<CSharpArgumentInfo> argumentInfo)
4464+
IMember CreateDynamicInvokeMemberSymbol(string name, CSharpArgumentInfo targetInfo, IReadOnlyList<CSharpArgumentInfo> argumentInfo, IReadOnlyList<IType> typeArguments)
44654465
{
44664466
var method = new FakeMethod(compilation, SymbolKind.Method) {
44674467
Name = name,
@@ -4475,7 +4475,16 @@ IMember CreateDynamicInvokeMemberSymbol(string name, CSharpArgumentInfo targetIn
44754475
parameters[i] = new DefaultParameter(DynamicArgumentType(argumentInfo[i]), argumentInfo[i].Name ?? string.Empty);
44764476
method.Parameters = parameters;
44774477
}
4478-
return method;
4478+
if (typeArguments.Count == 0)
4479+
return method;
4480+
// Explicit type arguments (a.Method<int>()): give the fake a matching set of type parameters,
4481+
// conventionally named T, T2, ..., and specialize it with the actual arguments like a real
4482+
// generic call would.
4483+
var typeParameters = new ITypeParameter[typeArguments.Count];
4484+
for (int i = 0; i < typeArguments.Count; i++)
4485+
typeParameters[i] = new DefaultTypeParameter(method, i, i == 0 ? "T" : "T" + (i + 1));
4486+
method.TypeParameters = typeParameters;
4487+
return SpecializedMethod.Create(method, new TypeParameterSubstitution(null, typeArguments));
44794488
}
44804489

44814490
/// <summary>

0 commit comments

Comments
 (0)