Browse Source

Implemented CaretReferencesRenderer - highlighting of all references to symbol under caret in the editor (VS2010 like).

Please provide feedback (usefulness, performance, highlight color, ...)
It should have no effect on editor performance - when moving caret by holding an arrow in the editor, nothing gets executed. After the caret stops for 100ms at one place, expression under caret is resolved to e.g. hide current highlight if no expression is under caret. Then, if the caret stays in place for 1000ms, "Find references in current document" is executed (on the main thread, but it's quite fast, maybe could be moved to background thread).
The timeouts are done using two DispatcherTimers.

Added "Find references in given document" (RefactoringService.FindReferencesLocal) to RefactoringService.
Refactored RefactoringService a bit, but public API and its behavior stays unchanged.

Fixed comment of DebuggerService.HandleToolTipRequest.


git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5725 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Martin Koníček 15 years ago
parent
commit
56a5829329
  1. 13
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  2. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj
  3. 123
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs
  4. 30
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
  5. 80
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs
  6. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs
  7. 8
      src/AddIns/Misc/SharpRefactoring/Project/Src/SwitchBodySnippetElement.cs
  8. 4
      src/Main/Base/Project/Src/Editor/ToolTipRequestEventArgs.cs
  9. 10
      src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs
  10. 26
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  11. 55
      src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs

13
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -162,19 +162,6 @@
</OptionPanel> </OptionPanel>
</Path> </Path>
<Path name = "/Workspace/Tools">
<Condition name="SolutionOpen" action="disable">
<MenuItem id = "DebuggerObjectGraphVisualizerShowCommand"
label = "Object graph visualizer"
class = "Debugger.AddIn.Visualizers.ObjectGraphVisualizerMenuCommand"/>
</Condition>
<Condition name="SolutionOpen" action="disable">
<MenuItem id = "DebuggerGridVisualizerShowCommand"
label = "Grid visualizer"
class = "Debugger.AddIn.Visualizers.GridVisualizerMenuCommand"/>
</Condition>
</Path>
<Path name="/SharpDevelop/Pads/ConsolePad/ToolBar"> <Path name="/SharpDevelop/Pads/ConsolePad/ToolBar">
<Include id="StandardCommands" path="/SharpDevelop/Pads/CommonConsole/ToolBar" /> <Include id="StandardCommands" path="/SharpDevelop/Pads/CommonConsole/ToolBar" />
<ToolbarItem class="ICSharpCode.SharpDevelop.Gui.Pads.SelectLanguageCommand" <ToolbarItem class="ICSharpCode.SharpDevelop.Gui.Pads.SelectLanguageCommand"

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj

@ -80,6 +80,7 @@
<Compile Include="Src\AvalonEditEditorUIService.cs" /> <Compile Include="Src\AvalonEditEditorUIService.cs" />
<Compile Include="Src\AvalonEditViewContent.cs" /> <Compile Include="Src\AvalonEditViewContent.cs" />
<Compile Include="Src\BracketHighlightRenderer.cs" /> <Compile Include="Src\BracketHighlightRenderer.cs" />
<Compile Include="Src\CaretReferencesRenderer.cs" />
<Compile Include="Src\ChooseEncodingDialog.xaml.cs"> <Compile Include="Src\ChooseEncodingDialog.xaml.cs">
<DependentUpon>ChooseEncodingDialog.xaml</DependentUpon> <DependentUpon>ChooseEncodingDialog.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
@ -87,6 +88,7 @@
<Compile Include="Src\CodeEditor.cs" /> <Compile Include="Src\CodeEditor.cs" />
<Compile Include="Src\CodeEditorAdapter.cs" /> <Compile Include="Src\CodeEditorAdapter.cs" />
<Compile Include="Src\CodeEditorView.cs" /> <Compile Include="Src\CodeEditorView.cs" />
<Compile Include="Src\ExpressionHighlightRenderer.cs" />
<Compile Include="Src\SharpDevelopTextEditor.cs" /> <Compile Include="Src\SharpDevelopTextEditor.cs" />
<Compile Include="Src\Commands\FoldingCommands.cs" /> <Compile Include="Src\Commands\FoldingCommands.cs" />
<Compile Include="Src\Commands\RunIncrementalSearch.cs" /> <Compile Include="Src\Commands\RunIncrementalSearch.cs" />

123
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs

@ -0,0 +1,123 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Konicek" email="martin.konicek@gmail.com"/>
// <version>$Revision: $</version>
// </file>
using System;
using System.Collections.Generic;
using System.Windows.Threading;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Refactoring;
namespace ICSharpCode.AvalonEdit.AddIn
{
/// <summary>
/// Description of CaretReferencesRenderer.
/// </summary>
public class CaretReferencesRenderer
{
/// <summary>
/// Delays the highlighting after the caret position changes, so that Find references does not get called too often.
/// </summary>
DispatcherTimer delayTimer;
const int delayMilliseconds = 1000;
DispatcherTimer delayMoveTimer;
const int delayMoveMilliseconds = 100;
CodeEditorView editorView;
ITextEditor Editor { get { return editorView.Adapter; } }
ExpressionHighlightRenderer highlightRenderer;
ResolveResult lastResolveResult;
public CaretReferencesRenderer(CodeEditorView editorView)
{
this.editorView = editorView;
this.highlightRenderer = new ExpressionHighlightRenderer(this.editorView.TextArea.TextView);
this.delayTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMilliseconds) };
this.delayTimer.Stop();
this.delayTimer.Tick += TimerTick;
this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) };
this.delayMoveTimer.Stop();
this.delayMoveTimer.Tick += TimerMoveTick;
this.editorView.TextArea.Caret.PositionChanged += CaretPositionChanged;
}
void TimerTick(object sender, EventArgs e)
{
this.delayTimer.Stop();
LoggingService.Info("tick");
// almost the same as DebuggerService.HandleToolTipRequest
var referencesToBeHighlighted = GetReferencesInCurrentFile(this.lastResolveResult);
this.highlightRenderer.SetHighlight(referencesToBeHighlighted);
}
void TimerMoveTick(object sender, EventArgs e)
{
LoggingService.Debug("move");
this.delayMoveTimer.Stop();
this.delayTimer.Stop();
var resolveResult = GetExpressionUnderCaret();
if (resolveResult == null) {
this.lastResolveResult = resolveResult;
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();
}
}
/// <summary>
/// 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.
/// </summary>
void CaretPositionChanged(object sender, EventArgs e)
{
this.delayMoveTimer.Stop();
this.delayMoveTimer.Start();
}
/// <summary>
/// Resolves the current expression under caret.
/// This gets called on every caret position change, so quite often.
/// </summary>
ResolveResult GetExpressionUnderCaret()
{
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);
}
/// <summary>
/// Finds references to resolved expression in the current file.
/// </summary>
List<Reference> GetReferencesInCurrentFile(ResolveResult resolveResult)
{
var references = RefactoringService.FindReferencesLocal(resolveResult, Editor.FileName, null);
if (references == null || references.Count == 0)
return null;
return references;
}
/// <summary>
/// Returns true if the 2 ResolveResults refer to the same symbol.
/// </summary>
bool SameResolveResult(ResolveResult resolveResult, ResolveResult resolveResult2)
{
return false;
}
}
}

30
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
public ITextEditor Adapter { get; set; } public ITextEditor Adapter { get; set; }
BracketHighlightRenderer bracketRenderer; BracketHighlightRenderer bracketRenderer;
CaretReferencesRenderer caretReferencesRenderer;
public CodeEditorView() public CodeEditorView()
{ {
@ -48,19 +49,16 @@ namespace ICSharpCode.AvalonEdit.AddIn
UpdateCustomizedHighlighting(); UpdateCustomizedHighlighting();
bracketRenderer = new BracketHighlightRenderer(this.TextArea.TextView); this.bracketRenderer = new BracketHighlightRenderer(this.TextArea.TextView);
this.caretReferencesRenderer = new CaretReferencesRenderer(this);
this.MouseHover += TextEditorMouseHover; this.MouseHover += TextEditorMouseHover;
this.MouseHoverStopped += TextEditorMouseHoverStopped; this.MouseHoverStopped += TextEditorMouseHoverStopped;
this.MouseLeave += TextEditorMouseLeave; this.MouseLeave += TextEditorMouseLeave;
this.TextArea.TextView.MouseDown += TextViewMouseDown; this.TextArea.TextView.MouseDown += TextViewMouseDown;
this.TextArea.Caret.PositionChanged += CaretPositionChanged; this.TextArea.Caret.PositionChanged += HighlightBrackets;
var editingKeyBindings = this.TextArea.DefaultInputHandler.Editing.InputBindings.OfType<KeyBinding>(); SetUpTabSnippetHandler();
var tabBinding = editingKeyBindings.Single(b => b.Key == Key.Tab && b.Modifiers == ModifierKeys.None);
this.TextArea.DefaultInputHandler.Editing.InputBindings.Remove(tabBinding);
var newTabBinding = new KeyBinding(new CustomTabCommand(this, tabBinding.Command), tabBinding.Key, tabBinding.Modifiers);
this.TextArea.DefaultInputHandler.Editing.InputBindings.Add(newTabBinding);
} }
protected override string FileName { protected override string FileName {
@ -71,13 +69,16 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
base.OnOptionChanged(e); base.OnOptionChanged(e);
if (e.PropertyName == "HighlightBrackets") if (e.PropertyName == "HighlightBrackets")
CaretPositionChanged(null, e); HighlightBrackets(null, e);
else if (e.PropertyName == "EnableFolding") else if (e.PropertyName == "EnableFolding")
UpdateParseInformation(); UpdateParseInformation();
} }
#region CaretPositionChanged - Bracket Highlighting #region CaretPositionChanged - Bracket Highlighting
void CaretPositionChanged(object sender, EventArgs e) /// <summary>
/// Highlights matching brackets.
/// </summary>
void HighlightBrackets(object sender, EventArgs e)
{ {
if (CodeEditorOptions.Instance.HighlightBrackets) { if (CodeEditorOptions.Instance.HighlightBrackets) {
/* /*
@ -97,6 +98,15 @@ namespace ICSharpCode.AvalonEdit.AddIn
#endregion #endregion
#region Custom Tab command (code snippet expansion) #region Custom Tab command (code snippet expansion)
void SetUpTabSnippetHandler()
{
var editingKeyBindings = this.TextArea.DefaultInputHandler.Editing.InputBindings.OfType<KeyBinding>();
var tabBinding = editingKeyBindings.Single(b => b.Key == Key.Tab && b.Modifiers == ModifierKeys.None);
this.TextArea.DefaultInputHandler.Editing.InputBindings.Remove(tabBinding);
var newTabBinding = new KeyBinding(new CustomTabCommand(this, tabBinding.Command), tabBinding.Key, tabBinding.Modifiers);
this.TextArea.DefaultInputHandler.Editing.InputBindings.Add(newTabBinding);
}
sealed class CustomTabCommand : ICommand sealed class CustomTabCommand : ICommand
{ {
CodeEditorView editor; CodeEditorView editor;
@ -202,7 +212,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
ITextMarker markerWithToolTip = markersAtOffset.FirstOrDefault(marker => marker.ToolTip != null); ITextMarker markerWithToolTip = markersAtOffset.FirstOrDefault(marker => marker.ToolTip != null);
if (markerWithToolTip != null) { if (markerWithToolTip != null) {
args.ShowToolTip(markerWithToolTip.ToolTip); args.SetToolTip(markerWithToolTip.ToolTip);
} }
} }

80
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ExpressionHighlightRenderer.cs

@ -0,0 +1,80 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Konicek" email="martin.konicek@gmail.com"/>
// <version>$Revision: $</version>
// </file>
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
{
/// <summary>
/// Highlights expressions (references to expression under current caret).
/// </summary>
public class ExpressionHighlightRenderer : IBackgroundRenderer
{
List<Reference> renderedReferences;
Pen borderPen;
Brush backgroundBrush;
TextView textView;
public void SetHighlight(List<Reference> 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.borderPen = new Pen(new SolidColorBrush(Color.FromRgb(70, 230, 70)), 1);
this.borderPen = new Pen(Brushes.Transparent, 1);
this.borderPen.Freeze();
this.backgroundBrush = new SolidColorBrush(Color.FromArgb(120, 60, 255, 60));
this.backgroundBrush.Freeze();
this.textView = textView;
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 = 1;
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);
}
}
}
}

2
src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs

@ -31,7 +31,7 @@ namespace Hornung.ResourceToolkit.ToolTips
ResourceResolveResult result = ResourceResolverService.Resolve(e.Editor.FileName, doc, logicPos.Y - 1, logicPos.X - 1, null); ResourceResolveResult result = ResourceResolverService.Resolve(e.Editor.FileName, doc, logicPos.Y - 1, logicPos.X - 1, null);
if (result != null && result.ResourceFileContent != null) { if (result != null && result.ResourceFileContent != null) {
e.ShowToolTip(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key)); e.SetToolTip(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key));
} }
} }

8
src/AddIns/Misc/SharpRefactoring/Project/Src/SwitchBodySnippetElement.cs

@ -184,7 +184,7 @@ namespace SharpRefactoring
/// Assuming that interactive mode of 'switch' snippet has currently finished in context, /// Assuming that interactive mode of 'switch' snippet has currently finished in context,
/// returns the switch condition that user entered. /// returns the switch condition that user entered.
/// </summary> /// </summary>
string GetSwitchConditionText(InsertionContext context, out int startOffset) string GetSwitchConditionText(InsertionContext context, out int conditionEndOffset)
{ {
var snippetActiveElements = context.ActiveElements.ToList(); var snippetActiveElements = context.ActiveElements.ToList();
if (snippetActiveElements.Count == 0) if (snippetActiveElements.Count == 0)
@ -194,17 +194,17 @@ namespace SharpRefactoring
throw new InvalidOperationException("Switch snippet condition should be " + typeof(IReplaceableActiveElement).Name); throw new InvalidOperationException("Switch snippet condition should be " + typeof(IReplaceableActiveElement).Name);
if (switchConditionElement.Segment == null) if (switchConditionElement.Segment == null)
throw new InvalidOperationException("Swith condition should have a start offset"); throw new InvalidOperationException("Swith condition should have a start offset");
startOffset = switchConditionElement.Segment.EndOffset - 1; conditionEndOffset = switchConditionElement.Segment.EndOffset - 1;
return switchConditionElement.Text; return switchConditionElement.Text;
} }
/// <summary> /// <summary>
/// Resolves the Dom.IReturnType of expression ending at offset, ie. the switch condition expression. /// Resolves the Dom.IReturnType of expression ending at offset, ie. the switch condition expression.
/// </summary> /// </summary>
IReturnType ResolveConditionType(string conditionExpression, int offset) IReturnType ResolveConditionType(string conditionExpression, int conditionEndOffset)
{ {
ExpressionResult expressionResult = new ExpressionResult(conditionExpression); ExpressionResult expressionResult = new ExpressionResult(conditionExpression);
Location location = this.Editor.Document.OffsetToPosition(offset); Location location = this.Editor.Document.OffsetToPosition(conditionEndOffset);
var result = ParserService.Resolve(expressionResult, location.Line, location.Column, this.Editor.FileName, this.Editor.Document.Text); var result = ParserService.Resolve(expressionResult, location.Line, location.Column, this.Editor.FileName, this.Editor.Document.Text);
return result.ResolvedType; return result.ResolvedType;
} }

4
src/Main/Base/Project/Src/Editor/ToolTipRequestEventArgs.cs

@ -38,9 +38,9 @@ namespace ICSharpCode.SharpDevelop.Editor
public object ContentToShow { get; set; } public object ContentToShow { get; set; }
/// <summary> /// <summary>
/// Shows the tool tip. /// Sets the tooltip to be shown.
/// </summary> /// </summary>
public void ShowToolTip(object content) public void SetToolTip(object content)
{ {
if (content == null) if (content == null)
throw new ArgumentNullException("content"); throw new ArgumentNullException("content");

10
src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

@ -246,9 +246,9 @@ namespace ICSharpCode.SharpDevelop.Debugging
#region Tool tips #region Tool tips
/// <summary> /// <summary>
/// Gets debugger tooltip information for the specified position. /// Gets debugger tooltip information for the specified position.
/// A descriptive text for the element or a DebuggerGridControl /// A descriptive string for the element or a DebuggerTooltipControl
/// showing its current value (when in debugging mode) can be returned /// showing its current value (when in debugging mode) can be returned
/// through the ToolTipInfo object. /// through the ToolTipRequestEventArgs.SetTooltip() method.
/// </summary> /// </summary>
internal static void HandleToolTipRequest(ToolTipRequestEventArgs e) internal static void HandleToolTipRequest(ToolTipRequestEventArgs e)
{ {
@ -276,15 +276,15 @@ namespace ICSharpCode.SharpDevelop.Debugging
} }
if (toolTipText != null) { if (toolTipText != null) {
if (debuggerCanShowValue && currentDebugger != null) { if (debuggerCanShowValue && currentDebugger != null) {
e.ShowToolTip(currentDebugger.GetTooltipControl(expressionResult.Expression)); e.SetToolTip(currentDebugger.GetTooltipControl(expressionResult.Expression));
} else { } else {
e.ShowToolTip(toolTipText); e.SetToolTip(toolTipText);
} }
} }
} else { } else {
#if DEBUG #if DEBUG
if (Control.ModifierKeys == Keys.Control) { if (Control.ModifierKeys == Keys.Control) {
e.ShowToolTip("no expr: " + expressionResult.ToString()); e.SetToolTip("no expr: " + expressionResult.ToString());
} }
#endif #endif
} }

26
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -182,7 +182,7 @@ namespace ICSharpCode.SharpDevelop
} }
#endregion #endregion
#region GetParser / ExpressionFinder /etc. #region GetParser / ExpressionFinder / Resolve / etc.
static readonly string[] DefaultTaskListTokens = {"HACK", "TODO", "UNDONE", "FIXME"}; static readonly string[] DefaultTaskListTokens = {"HACK", "TODO", "UNDONE", "FIXME"};
/// <summary> /// <summary>
@ -238,6 +238,9 @@ namespace ICSharpCode.SharpDevelop
return null; return null;
} }
/// <summary>
/// Resolves given ExpressionResult.
/// </summary>
public static ResolveResult Resolve(ExpressionResult expressionResult, public static ResolveResult Resolve(ExpressionResult expressionResult,
int caretLineNumber, int caretColumn, int caretLineNumber, int caretColumn,
string fileName, string fileContent) string fileName, string fileContent)
@ -252,6 +255,27 @@ namespace ICSharpCode.SharpDevelop
} }
return null; return null;
} }
/// <summary>
/// Resolves expression at given position.
/// That is, finds ExpressionResult at that position and
/// calls the overload Resolve(ExpressionResult,...).
/// </summary>
public static ResolveResult Resolve(int caretLine, int caretColumn, IDocument document, string fileName)
{
IExpressionFinder expressionFinder = GetExpressionFinder(fileName);
if (expressionFinder == null)
return null;
if (caretColumn > document.GetLine(caretLine).Length)
return null;
string documentText = document.Text;
var expressionResult = expressionFinder.FindFullExpression(documentText, document.PositionToOffset(caretLine, caretColumn));
string expression = (expressionResult.Expression ?? "").Trim();
if (expression.Length > 0) {
return Resolve(expressionResult, caretLine, caretColumn, fileName, documentText);
} else
return null;
}
#endregion #endregion
#region GetParseableFileContent #region GetParseableFileContent

55
src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs

@ -88,54 +88,78 @@ namespace ICSharpCode.SharpDevelop.Refactoring
/// Find all references to the specified member. /// Find all references to the specified member.
/// </summary> /// </summary>
public static List<Reference> FindReferences(IMember member, IProgressMonitor progressMonitor) public static List<Reference> FindReferences(IMember member, IProgressMonitor progressMonitor)
{
return FindReferences(member, null, progressMonitor);
}
static List<Reference> FindReferences(IMember member, string fileName, IProgressMonitor progressMonitor)
{ {
if (member == null) if (member == null)
throw new ArgumentNullException("member"); throw new ArgumentNullException("member");
return RunFindReferences(member.DeclaringType, member, false, progressMonitor); return RunFindReferences(member.DeclaringType, member, fileName, progressMonitor);
} }
/// <summary> /// <summary>
/// Find all references to the specified class. /// Find all references to the specified class.
/// </summary> /// </summary>
public static List<Reference> FindReferences(IClass @class, IProgressMonitor progressMonitor) public static List<Reference> FindReferences(IClass @class, IProgressMonitor progressMonitor)
{
return FindReferences(@class, null, progressMonitor);
}
static List<Reference> FindReferences(IClass @class, string fileName, IProgressMonitor progressMonitor)
{ {
if (@class == null) if (@class == null)
throw new ArgumentNullException("class"); throw new ArgumentNullException("class");
return RunFindReferences(@class, null, false, progressMonitor); return RunFindReferences(@class, null, fileName, progressMonitor);
} }
/// <summary> /// <summary>
/// Find all references to the resolved entity. /// Find all references to the resolved entity.
/// </summary> /// </summary>
public static List<Reference> FindReferences(ResolveResult entity, IProgressMonitor progressMonitor) public static List<Reference> FindReferences(ResolveResult entity, IProgressMonitor progressMonitor)
{
return FindReferences(entity, null, progressMonitor);
}
/// <summary>
/// Finds all references to the resolved entity, only in the file where the entity was resolved.
/// </summary>
public static List<Reference> FindReferencesLocal(ResolveResult entity, string fileName, IProgressMonitor progressMonitor)
{
return FindReferences(entity, fileName, progressMonitor);
}
static List<Reference> FindReferences(ResolveResult entity, string fileName, IProgressMonitor progressMonitor)
{ {
if (entity == null) if (entity == null)
throw new ArgumentNullException("entity"); throw new ArgumentNullException("entity");
if (entity is LocalResolveResult) { if (entity is LocalResolveResult) {
return RunFindReferences(entity.CallingClass, (entity as LocalResolveResult).Field, true, progressMonitor); return RunFindReferences(entity.CallingClass, (entity as LocalResolveResult).Field,
entity.CallingClass.CompilationUnit.FileName, progressMonitor);
} else if (entity is TypeResolveResult) { } else if (entity is TypeResolveResult) {
return FindReferences((entity as TypeResolveResult).ResolvedClass, progressMonitor); return FindReferences((entity as TypeResolveResult).ResolvedClass, fileName, progressMonitor);
} else if (entity is MemberResolveResult) { } else if (entity is MemberResolveResult) {
return FindReferences((entity as MemberResolveResult).ResolvedMember, progressMonitor); return FindReferences((entity as MemberResolveResult).ResolvedMember, fileName, progressMonitor);
} else if (entity is MethodGroupResolveResult) { } else if (entity is MethodGroupResolveResult) {
IMethod method = (entity as MethodGroupResolveResult).GetMethodIfSingleOverload(); IMethod method = (entity as MethodGroupResolveResult).GetMethodIfSingleOverload();
if (method != null) { if (method != null) {
return FindReferences(method, progressMonitor); return FindReferences(method, fileName, progressMonitor);
} }
} else if (entity is MixedResolveResult) { } else if (entity is MixedResolveResult) {
return FindReferences((entity as MixedResolveResult).PrimaryResult, progressMonitor); return FindReferences((entity as MixedResolveResult).PrimaryResult, fileName, progressMonitor);
} }
return null; return null;
} }
/// <summary> /// <summary>
/// This method can be used in three modes: /// This method can be used in three modes:
/// 1. Find references to classes (parentClass = targetClass, member = null, isLocal = false) /// 1. Find references to classes (parentClass = targetClass, member = null, fileName = null)
/// 2. Find references to members (parentClass = parent, member = member, isLocal = false) /// 2. Find references to members (parentClass = parent, member = member, fileName = null)
/// 3. Find references to local variables (parentClass = parent, member = local var as field, isLocal = true) /// 3. Find references to local variables (parentClass = parent, member = local var as field, fileName = parent.CompilationUnit.FileName)
/// </summary> /// </summary>
static List<Reference> RunFindReferences(IClass ownerClass, IMember member, static List<Reference> RunFindReferences(IClass ownerClass, IMember member,
bool isLocal, string fileName,
IProgressMonitor progressMonitor) IProgressMonitor progressMonitor)
{ {
if (ParserService.LoadSolutionProjectsThreadRunning) { if (ParserService.LoadSolutionProjectsThreadRunning) {
@ -145,10 +169,12 @@ namespace ICSharpCode.SharpDevelop.Refactoring
return null; return null;
} }
List<ProjectItem> files; List<ProjectItem> files;
if (isLocal) { if (!string.IsNullOrEmpty(fileName)) {
// search just in given file
files = new List<ProjectItem>(); files = new List<ProjectItem>();
files.Add(FindItem(ownerClass.CompilationUnit.FileName)); files.Add(FindItem(fileName));
} else { } else {
// search in all possible files
ownerClass = ownerClass.GetCompoundClass(); ownerClass = ownerClass.GetCompoundClass();
files = GetPossibleFiles(ownerClass, member); files = GetPossibleFiles(ownerClass, member);
} }
@ -169,7 +195,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
ITextBuffer content = entry.GetContent(); ITextBuffer content = entry.GetContent();
if (content != null) { if (content != null) {
AddReferences(references, ownerClass, member, isLocal, entry.FileName, content.Text); AddReferences(references, ownerClass, member, entry.FileName, content.Text);
} }
} }
@ -181,7 +207,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring
/// </summary> /// </summary>
static void AddReferences(List<Reference> list, static void AddReferences(List<Reference> list,
IClass parentClass, IMember member, IClass parentClass, IMember member,
bool isLocal,
string fileName, string fileContent) string fileName, string fileContent)
{ {
TextFinder textFinder; // the class used to find the position to resolve TextFinder textFinder; // the class used to find the position to resolve

Loading…
Cancel
Save