diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index d017b515a..fc027541e 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -288,6 +288,17 @@ namespace ICSharpCode.ILSpy.Languages return new RichText(text, model); } + public override RichText GetRichText(IType type) + { + ArgumentNullException.ThrowIfNull(type); + var output = new StringWriter(); + var decoratedWriter = new TextWriterTokenWriter(output); + var writer = new CSharpHighlightingTokenWriter(TokenWriter.InsertRequiredSpaces(decoratedWriter), locatable: decoratedWriter); + var astBuilder = new TypeSystemAstBuilder { AlwaysUseShortTypeNames = true }; + astBuilder.ConvertType(type).AcceptVisitor(new CSharpOutputVisitor(writer, FormattingOptionsFactory.CreateAllman())); + return new RichText(output.ToString(), writer.HighlightingModel); + } + static void EmboldenTypeNames(string text, RichTextModel model) { var highlighting = HighlightingManager.Instance.GetDefinition("C#"); diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 3befc61f7..b7931277f 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -188,6 +188,12 @@ namespace ICSharpCode.ILSpy.Languages public virtual RichText GetRichText(IEntity entity, ConversionFlags conversionFlags, bool boldTypeNames = false) => new(EntityToString(entity, conversionFlags)); + /// + /// Renders a bare type (e.g. a local variable's type, or dynamic) as rich text for a hover. + /// + public virtual RichText GetRichText(IType type) + => new(TypeToString(type)); + public virtual void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, TypeToString(type)); diff --git a/ILSpy/TextView/DecompilerTextView.axaml.cs b/ILSpy/TextView/DecompilerTextView.axaml.cs index a7dc507cf..4949e84ef 100644 --- a/ILSpy/TextView/DecompilerTextView.axaml.cs +++ b/ILSpy/TextView/DecompilerTextView.axaml.cs @@ -1471,6 +1471,14 @@ namespace ICSharpCode.ILSpy.TextView internal HoverContent? BuildHoverContent(DecompilerTabPageModel model, ReferenceSegment segment) { var language = model.Language; + if (segment.Reference is Decompiler.IL.ILVariable variable && language != null) + { + // Local variables have no metadata symbol, so render the declared type and name directly. + string kind = variable.Kind == Decompiler.IL.VariableKind.Parameter ? "parameter" : "local variable"; + var localRenderer = CreateTooltipRenderer(); + localRenderer.AddSignatureBlock(new RichText($"({kind}) ") + language.GetRichText(variable.Type) + new RichText($" {variable.Name}")); + return new HoverContent(localRenderer.CreateView(), IsRich: true); + } var resolved = ResolveEntity(model, segment.Reference); switch (resolved) {