From 3f999348cf969d3e5fff1e81937d2bec724f98bc Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 12 Feb 2014 23:34:41 +0100 Subject: [PATCH] first implementation of #247: Reimplement 'highlight symbols' (CaretReferencesRenderer) missing: - ctor/method calls are not highlighted properly - not bound to options --- .../Project/Src/CSharpLanguageBinding.cs | 20 ++ .../Project/Src/CSharpSemanticHighlighter.cs | 98 ++++++++- .../AvalonEdit.AddIn/AvalonEdit.AddIn.csproj | 2 - .../Src/CaretReferencesRenderer.cs | 202 ------------------ .../Src/ExpressionHighlightRenderer.cs | 97 --------- .../Highlighting/HighlightingBrush.cs | 11 +- .../Analysis/SemanticHighlightingVisitor.cs | 4 +- .../TypeSystem/TypeSystemExtensions.cs | 15 ++ 8 files changed, 139 insertions(+), 310 deletions(-) delete mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs delete mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 9852a5c8c4..e6b12f2b51 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -19,7 +19,10 @@ using System; using System.Collections.Generic; +using System.Threading; +using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; using CSharpBinding.Completion; using CSharpBinding.FormattingStrategy; @@ -58,12 +61,15 @@ namespace CSharpBinding IssueManager inspectionManager; IList contextActionProviders; CodeManipulation codeManipulation; + CSharpSemanticHighlighter highlighter; + CancellationTokenSource caretMovementTokenSource; public void Attach(ITextEditor editor) { this.editor = editor; inspectionManager = new IssueManager(editor); codeManipulation = new CodeManipulation(editor); + this.editor.Caret.LocationChanged += CaretLocationChanged; if (!editor.ContextActionProviders.IsReadOnly) { contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); @@ -81,7 +87,21 @@ namespace CSharpBinding if (contextActionProviders != null) { editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains); } + this.editor.Caret.LocationChanged -= CaretLocationChanged; this.editor = null; } + + void CaretLocationChanged(object sender, EventArgs e) + { + if (highlighter == null) + highlighter = editor.GetService(); + if (highlighter == null) + return; + if (caretMovementTokenSource != null) + caretMovementTokenSource.Cancel(); + caretMovementTokenSource = new CancellationTokenSource(); + var rr = SD.ParserService.Resolve(editor.FileName, editor.Caret.Location, editor.Document, cancellationToken: caretMovementTokenSource.Token); + highlighter.SetCurrentSymbol(rr.GetSymbol()); + } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs index 6fc48951de..49b022168d 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs @@ -18,14 +18,19 @@ using System; using System.Collections.Generic; +using System.ComponentModel.Design; using System.Diagnostics; using System.Linq; +using System.Windows.Media; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Core; using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Analysis; +using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Parser; @@ -50,6 +55,9 @@ namespace CSharpBinding int lineNumber; HighlightedLine line; CSharpFullParseInformation parseInfo; + ISymbolReference currentSymbolReference; + IResolveVisitorNavigator currentNavigator; + HighlightingColor symbolReferenceColor; #region Constructor + Dispose public CSharpSemanticHighlighter(IDocument document) @@ -66,6 +74,7 @@ namespace CSharpBinding this.enumerationTypeColor = this.valueKeywordColor; this.typeParameterTypeColor = this.referenceTypeColor; this.delegateTypeColor = this.referenceTypeColor; + this.symbolReferenceColor = new HighlightingColor { Background = new SimpleHighlightingBrush(DefaultFillColor) }; this.methodDeclarationColor = this.methodCallColor = highlighting.GetNamedColor("MethodCall"); //this.eventDeclarationColor = this.eventAccessColor = defaultTextColor; @@ -92,6 +101,7 @@ namespace CSharpBinding SD.ParserService.ParseInformationUpdated += ParserService_ParseInformationUpdated; SD.ParserService.LoadSolutionProjectsThread.Finished += ParserService_LoadSolutionProjectsThreadEnded; eventHandlersAreRegistered = true; + document.GetService().AddService(typeof(CSharpSemanticHighlighter), this); } } @@ -101,6 +111,7 @@ namespace CSharpBinding SD.ParserService.ParseInformationUpdated -= ParserService_ParseInformationUpdated; SD.ParserService.LoadSolutionProjectsThread.Finished -= ParserService_LoadSolutionProjectsThreadEnded; eventHandlersAreRegistered = false; + document.GetService().RemoveService(typeof(CSharpSemanticHighlighter)); } this.resolver = null; this.parseInfo = null; @@ -174,10 +185,7 @@ namespace CSharpBinding void ParserService_LoadSolutionProjectsThreadEnded(object sender, EventArgs e) { - cachedLines.Clear(); - invalidLines.Clear(); - forceParseOnNextRefresh = true; - OnHighlightingStateChanged(1, document.LineCount); + InvalidateAll(); } void ParserService_ParseInformationUpdated(object sender, ParseInformationEventArgs e) @@ -389,6 +397,88 @@ namespace CSharpBinding }); } } + + protected override void Colorize(AstNode node, HighlightingColor color) + { + if (currentSymbolReference != null && currentNavigator == null) + currentNavigator = InitNavigator(); + + if (currentNavigator != null) { + var resolverNode = node; + while (CSharpAstResolver.IsUnresolvableNode(resolverNode) && resolverNode.Parent != null) + resolverNode = resolverNode.Parent; + currentNavigator.Resolved(resolverNode, resolver.Resolve(resolverNode)); + } + base.Colorize(node, color); + } + + protected override void Colorize(Identifier identifier, ResolveResult rr) + { + if (currentSymbolReference != null && currentNavigator == null) + currentNavigator = InitNavigator(); + + if (currentNavigator != null) { + currentNavigator.Resolved(identifier, rr); + } + base.Colorize(identifier, rr); + } + + public readonly Color DefaultFillColor = Color.FromArgb(22, 30, 130, 255); + + public void SetCurrentSymbol(ISymbol symbol) + { + currentNavigator = null; + currentSymbolReference = null; + if (symbol != null) + currentSymbolReference = symbol.ToReference(); + InvalidateAll(); + } + + void InvalidateAll() + { + cachedLines.Clear(); + invalidLines.Clear(); + forceParseOnNextRefresh = true; + OnHighlightingStateChanged(1, document.LineCount); + } + + FindReferences findReferences = new FindReferences(); + + IResolveVisitorNavigator InitNavigator() + { + if (currentSymbolReference == null) return null; + var compilation = resolver.Compilation; + var symbol = currentSymbolReference.Resolve(compilation.TypeResolveContext); + var searchScopes = findReferences.GetSearchScopes(symbol); + if (searchScopes.Count == 0) + return null; + var navigators = new IResolveVisitorNavigator[searchScopes.Count]; + for (int i = 0; i < navigators.Length; i++) { + navigators[i] = searchScopes[i].GetNavigator(compilation, Colorize); + } + IResolveVisitorNavigator combinedNavigator; + if (searchScopes.Count == 1) { + combinedNavigator = navigators[0]; + } else { + combinedNavigator = new CompositeResolveVisitorNavigator(navigators); + } + + return combinedNavigator; + } + + void Colorize(AstNode node, ResolveResult result) + { + Identifier identifier = node.GetChildByRole(Roles.Identifier); + if (!identifier.IsNull) + AddMarker(identifier.StartLocation, identifier.EndLocation); + else + AddMarker(node.StartLocation, node.EndLocation); + } + + void AddMarker(TextLocation start, TextLocation end) + { + Colorize(start, end, symbolReferenceColor); + } #endregion } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj index d6419f6fe7..4fa4a0c07e 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj @@ -134,7 +134,6 @@ - ChooseEncodingDialog.xaml Code @@ -143,7 +142,6 @@ - diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs deleted file mode 100644 index 2ec340204c..0000000000 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Windows.Threading; - -using ICSharpCode.AvalonEdit.AddIn.Options; -using ICSharpCode.Core; -using ICSharpCode.SharpDevelop; -using ICSharpCode.SharpDevelop.Editor; -using ICSharpCode.SharpDevelop.Gui; -using ICSharpCode.SharpDevelop.Refactoring; - -namespace ICSharpCode.AvalonEdit.AddIn -{ - /* /// - /// In the code editor, highlights all references to the expression under the caret (for better code readability). - /// - public class CaretReferencesRenderer - { - /// - /// Delays the Resolve check so that it does not get called too often when user holds an arrow. - /// - DispatcherTimer delayMoveTimer; - const int delayMoveMs = 100; - - /// - /// Delays the Find references (and highlight) after the caret stays at one point for a while. - /// - DispatcherTimer delayTimer; - const int delayMs = 800; - - /// - /// Maximum time for Find references. After this time it gets cancelled and no highlight is displayed. - /// Useful for very large files. - /// - const int findReferencesTimeoutMs = 200; - - CodeEditorView editorView; - ITextEditor Editor { get { return editorView.Adapter; } } - - ExpressionHighlightRenderer highlightRenderer; - ResolveResult lastResolveResult; - - public bool IsEnabled - { - get { - string fileName = this.Editor.FileName; - return CodeEditorOptions.Instance.HighlightSymbol && (fileName.EndsWith(".cs") || fileName.EndsWith(".vb")); - } - } - - /// - /// In the code editor, highlights all references to the expression under the caret (for better code readability). - /// - public CaretReferencesRenderer(CodeEditorView editorView) - { - this.editorView = editorView; - this.highlightRenderer = new ExpressionHighlightRenderer(this.editorView.TextArea.TextView); - this.delayTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMs) }; - this.delayTimer.Stop(); - this.delayTimer.Tick += TimerTick; - this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMs) }; - this.delayMoveTimer.Stop(); - this.delayMoveTimer.Tick += TimerMoveTick; - this.editorView.TextArea.Caret.PositionChanged += CaretPositionChanged; - // fixes SD-1873 - Unhandled WPF Exception when deleting text in text editor - // clear highlights to avoid exceptions when trying to draw highlights in - // locations that have been deleted already. - this.editorView.Document.Changed += delegate { lastResolveResult = null; ClearHighlight(); }; - } - - public void ClearHighlight() - { - this.highlightRenderer.ClearHighlight(); - } - - /// - /// In the current document, highlights all references to the expression - /// which is currently under the caret (local variable, class, property). - /// This gets called on every caret position change, so quite often. - /// - void CaretPositionChanged(object sender, EventArgs e) - { - Restart(this.delayMoveTimer); - } - - void TimerTick(object sender, EventArgs e) - { - this.delayTimer.Stop(); - - if (!IsEnabled) - return; - var referencesToBeHighlighted = FindReferencesInCurrentFile(this.lastResolveResult); - this.highlightRenderer.SetHighlight(referencesToBeHighlighted); - } - - void TimerMoveTick(object sender, EventArgs e) - { - this.delayMoveTimer.Stop(); - this.delayTimer.Stop(); - - if (!IsEnabled) - return; - - var resolveResult = GetExpressionAtCaret(); - if (resolveResult == null) { - this.lastResolveResult = null; - this.highlightRenderer.ClearHighlight(); - return; - } - // caret is over symbol and that symbol is different from the last time - if (!SameResolveResult(resolveResult, lastResolveResult)) - { - this.lastResolveResult = resolveResult; - this.highlightRenderer.ClearHighlight(); - this.delayTimer.Start(); - } else { - // highlight stays the same, both timers are stopped (will start again when caret moves) - } - } - - /// - /// Resolves the current expression under caret. - /// This gets called on every caret position change, so quite often. - /// - ResolveResult GetExpressionAtCaret() - { - if (string.IsNullOrEmpty(Editor.FileName) || ParserService.LoadSolutionProjectsThreadRunning) - return null; - int line = Editor.Caret.Position.Line; - int column = Editor.Caret.Position.Column; - return ParserService.Resolve(line, column, Editor.Document, Editor.FileName); - } - - /// - /// Finds references to resolved expression in the current file. - /// - List FindReferencesInCurrentFile(ResolveResult resolveResult) - { - if (resolveResult == null) - return null; - var cancellationTokenSource = new CancellationTokenSource(); - using (new Timer( - delegate { - LoggingService.Debug("Aborting FindReferencesInCurrentFile due to timeout"); - cancellationTokenSource.Cancel(); - }, null, findReferencesTimeoutMs, Timeout.Infinite)) - { - var progressMonitor = new DummyProgressMonitor(); - progressMonitor.CancellationToken = cancellationTokenSource.Token; - var references = RefactoringService.FindReferencesLocal(resolveResult, Editor.FileName, progressMonitor); - if (references == null || references.Count == 0) - return null; - return references; - } - } - - /// - /// Returns true if the 2 ResolveResults refer to the same symbol. - /// So that when caret moves but stays inside the same symbol, symbol stays highlighted. - /// - bool SameResolveResult(ResolveResult resolveResult, ResolveResult resolveResult2) - { - //if (resolveResult == null && resolveResult2 == null) - // return true; - //if (resolveResult == null && resolveResult2 != null) - // return false; - //if (resolveResult != null && resolveResult2 == null) - // return false; - // TODO determine if 2 ResolveResults refer to the same symbol - return false; - } - - /// - /// Restarts a timer. - /// - void Restart(DispatcherTimer timer) - { - timer.Stop(); - timer.Start(); - } - } - */ -} diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs deleted file mode 100644 index 4b511c9149..0000000000 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Diagnostics; -using System.Windows.Media; -using System.Collections.Generic; - -using ICSharpCode.AvalonEdit.Document; -using ICSharpCode.AvalonEdit.Rendering; -using ICSharpCode.SharpDevelop.Editor; -using ICSharpCode.SharpDevelop.Refactoring; - -namespace ICSharpCode.AvalonEdit.AddIn -{ - /* - /// - /// Highlights expressions (references to expression under current caret). - /// - public class ExpressionHighlightRenderer : IBackgroundRenderer - { - List renderedReferences; - Pen borderPen; - Brush backgroundBrush; - TextView textView; - public readonly Color DefaultBorderColor = Color.FromArgb(52, 30, 130, 255); //Color.FromArgb(180, 70, 230, 70)) - public readonly Color DefaultFillColor = Color.FromArgb(22, 30, 130, 255); //Color.FromArgb(40, 60, 255, 60) - readonly int borderThickness = 1; - readonly int cornerRadius = 1; - - public void SetHighlight(List renderedReferences) - { - if (this.renderedReferences != renderedReferences) { - this.renderedReferences = renderedReferences; - textView.InvalidateLayer(this.Layer); - } - } - - public void ClearHighlight() - { - this.SetHighlight(null); - } - - public ExpressionHighlightRenderer(TextView textView) - { - if (textView == null) - throw new ArgumentNullException("textView"); - this.textView = textView; - this.borderPen = new Pen(new SolidColorBrush(DefaultBorderColor), borderThickness); - this.backgroundBrush = new SolidColorBrush(DefaultFillColor); - this.borderPen.Freeze(); - this.backgroundBrush.Freeze(); - this.textView.BackgroundRenderers.Add(this); - } - - public KnownLayer Layer { - get { - return KnownLayer.Selection; - } - } - - public void Draw(TextView textView, DrawingContext drawingContext) - { - if (this.renderedReferences == null) - return; - BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder(); - builder.CornerRadius = cornerRadius; - builder.AlignToMiddleOfPixels = true; - foreach (var reference in this.renderedReferences) { - builder.AddSegment(textView, new TextSegment() { - StartOffset = reference.Offset, - Length = reference.Length }); - builder.CloseFigure(); - } - Geometry geometry = builder.CreateGeometry(); - if (geometry != null) { - drawingContext.DrawGeometry(backgroundBrush, borderPen, geometry); - } - } - } - */ -} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs index 8bed0aa4aa..a3e908440e 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs @@ -58,23 +58,26 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// Highlighting brush implementation that takes a frozen brush. /// [Serializable] - sealed class SimpleHighlightingBrush : HighlightingBrush, ISerializable + public sealed class SimpleHighlightingBrush : HighlightingBrush, ISerializable { readonly SolidColorBrush brush; - public SimpleHighlightingBrush(SolidColorBrush brush) + internal SimpleHighlightingBrush(SolidColorBrush brush) { brush.Freeze(); this.brush = brush; } + /// public SimpleHighlightingBrush(Color color) : this(new SolidColorBrush(color)) {} + /// public override Brush GetBrush(ITextRunConstructionContext context) { return brush; } - + + /// public override string ToString() { return brush.ToString(); @@ -91,6 +94,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting info.AddValue("color", brush.Color.ToString(CultureInfo.InvariantCulture)); } + /// public override bool Equals(object obj) { SimpleHighlightingBrush other = obj as SimpleHighlightingBrush; @@ -99,6 +103,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting return this.brush.Color.Equals(other.brush.Color); } + /// public override int GetHashCode() { return brush.Color.GetHashCode(); diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs index 4979fd0a6a..ac06ae29bd 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/SemanticHighlightingVisitor.cs @@ -94,7 +94,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis protected abstract void Colorize(TextLocation start, TextLocation end, TColor color); #region Colorize helper methods - protected void Colorize(Identifier identifier, ResolveResult rr) + protected virtual void Colorize(Identifier identifier, ResolveResult rr) { if (identifier.IsNull) return; @@ -141,7 +141,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis VisitIdentifier(identifier); // un-colorize contextual keywords } - protected void Colorize(AstNode node, TColor color) + protected virtual void Colorize(AstNode node, TColor color) { if (node.IsNull) return; diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs index 115ad07d48..51e736816d 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs @@ -765,5 +765,20 @@ namespace ICSharpCode.NRefactory.TypeSystem return assembly.GetTypeDefinition (new TopLevelTypeName (namespaceName, name, typeParameterCount)); } #endregion + + #region ResolveResult + public static ISymbol GetSymbol(this ResolveResult rr) + { + if (rr is LocalResolveResult) { + return ((LocalResolveResult)rr).Variable; + } else if (rr is MemberResolveResult) { + return ((MemberResolveResult)rr).Member; + } else if (rr is TypeResolveResult) { + return ((TypeResolveResult)rr).Type.GetDefinition(); + } + + return null; + } + #endregion } }