Browse Source

Applied patch by Christian Hornung: Fixes for refactoring indexer expressions

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.0@1320 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
ce31426dcb
  1. 15
      src/Main/Base/Project/Src/Dom/LanguageProperties.cs
  2. 44
      src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs
  3. 84
      src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs
  4. 13
      src/Main/Base/Project/Src/TextEditor/Commands/ClassMemberMenuBuilder.cs

15
src/Main/Base/Project/Src/Dom/LanguageProperties.cs

@ -115,6 +115,15 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
} }
/// <summary>
/// Gets the token that denotes a possible beginning of an indexer expression.
/// </summary>
public virtual string IndexerExpressionStartToken {
get {
return "[";
}
}
public virtual bool ShowInNamespaceCompletion(IClass c) public virtual bool ShowInNamespaceCompletion(IClass c)
{ {
return true; return true;
@ -187,6 +196,12 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
} }
public override string IndexerExpressionStartToken {
get {
return "(";
}
}
public override bool ShowInNamespaceCompletion(IClass c) public override bool ShowInNamespaceCompletion(IClass c)
{ {
foreach (IAttribute attr in c.Attributes) { foreach (IAttribute attr in c.Attributes) {

44
src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs

@ -67,22 +67,35 @@ namespace ICSharpCode.SharpDevelop.Refactoring
} }
// Include menu for member that has been clicked on // Include menu for member that has been clicked on
ResolveResult rr = ResolveAtCaret(textEditorControl, textArea); IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textEditorControl.FileName);
ExpressionResult expressionResult;
ResolveResult rr;
int insertIndex = resultItems.Count; // Insert items at this position to get the outermost expression first, followed by the inner expressions (if any).
expressionResult = FindFullExpressionAtCaret(textArea, expressionFinder);
repeatResolve:
rr = ResolveExpressionAtCaret(textArea, expressionResult);
item = null; item = null;
if (rr is MethodResolveResult) { if (rr is MethodResolveResult) {
item = MakeItem(definitions, ((MethodResolveResult)rr).GetMethodIfSingleOverload()); item = MakeItem(definitions, ((MethodResolveResult)rr).GetMethodIfSingleOverload());
} else if (rr is MemberResolveResult) { } else if (rr is MemberResolveResult) {
item = MakeItem(definitions, ((MemberResolveResult)rr).ResolvedMember); MemberResolveResult mrr = (MemberResolveResult)rr;
item = MakeItem(definitions, mrr.ResolvedMember);
if (RefactoringService.FixIndexerExpression(expressionFinder, ref expressionResult, mrr)) {
if (item != null) {
resultItems.Insert(insertIndex, item);
}
// Include menu for the underlying expression of the
// indexer expression as well.
goto repeatResolve;
}
} else if (rr is TypeResolveResult) { } else if (rr is TypeResolveResult) {
item = MakeItem(definitions, ((TypeResolveResult)rr).ResolvedClass); item = MakeItem(definitions, ((TypeResolveResult)rr).ResolvedClass);
} else if (rr is LocalResolveResult) { } else if (rr is LocalResolveResult) {
item = MakeItem((LocalResolveResult)rr, caretLine + 1 == ((LocalResolveResult)rr).Field.Region.BeginLine); item = MakeItem((LocalResolveResult)rr, caretLine + 1 == ((LocalResolveResult)rr).Field.Region.BeginLine);
insertIndex = 0; // Insert local variable menu item at the topmost position.
} }
if (item != null) { if (item != null) {
if (rr is LocalResolveResult) resultItems.Insert(insertIndex, item);
resultItems.Insert(0, item);
else
resultItems.Add(item);
} }
// Include menu for current class and method // Include menu for current class and method
@ -200,16 +213,19 @@ namespace ICSharpCode.SharpDevelop.Refactoring
return item; return item;
} }
ResolveResult ResolveAtCaret(TextEditorControl textEditorControl, TextArea textArea) static ExpressionResult FindFullExpressionAtCaret(TextArea textArea, IExpressionFinder expressionFinder)
{
if (expressionFinder != null) {
return expressionFinder.FindFullExpression(textArea.Document.TextContent, textArea.Caret.Offset);
} else {
return new ExpressionResult(null);
}
}
static ResolveResult ResolveExpressionAtCaret(TextArea textArea, ExpressionResult expressionResult)
{ {
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textEditorControl.FileName);
if (expressionFinder == null)
return null;
IDocument doc = textArea.Document;
string textContent = doc.TextContent;
ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, textArea.Caret.Offset);
if (expressionResult.Expression != null) { if (expressionResult.Expression != null) {
return ParserService.Resolve(expressionResult, textArea.Caret.Line + 1, textArea.Caret.Column + 1, textArea.MotherTextEditorControl.FileName, textContent); return ParserService.Resolve(expressionResult, textArea.Caret.Line + 1, textArea.Caret.Column + 1, textArea.MotherTextEditorControl.FileName, textArea.Document.TextContent);
} }
return null; return null;
} }

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

@ -149,6 +149,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
{ {
string lowerFileContent = fileContent.ToLower(); string lowerFileContent = fileContent.ToLower();
string searchedText; // the text that is searched for string searchedText; // the text that is searched for
bool searchingIndexer = false;
if (member == null) { if (member == null) {
searchedText = parentClass.Name.ToLower(); searchedText = parentClass.Name.ToLower();
@ -158,28 +159,40 @@ namespace ICSharpCode.SharpDevelop.Refactoring
// (examples: derived classes, partial classes) // (examples: derived classes, partial classes)
if (member is IMethod && ((IMethod)member).IsConstructor) if (member is IMethod && ((IMethod)member).IsConstructor)
searchedText = parentClass.Name.ToLower(); searchedText = parentClass.Name.ToLower();
else else {
searchedText = member.Name.ToLower(); if (member is IProperty && ((IProperty)member).IsIndexer) {
searchingIndexer = true;
searchedText = GetIndexerExpressionStartToken(fileName);
} else {
searchedText = member.Name.ToLower();
}
}
} }
int pos = -1; int pos = -1;
int exprPos;
IExpressionFinder expressionFinder = null; IExpressionFinder expressionFinder = null;
while ((pos = lowerFileContent.IndexOf(searchedText, pos + 1)) >= 0) { while ((pos = lowerFileContent.IndexOf(searchedText, pos + 1)) >= 0) {
if (pos > 0 && char.IsLetterOrDigit(fileContent, pos - 1)) { if (!searchingIndexer) {
continue; // memberName is not a whole word (a.SomeName cannot reference Name) if (pos > 0 && char.IsLetterOrDigit(fileContent, pos - 1)) {
} continue; // memberName is not a whole word (a.SomeName cannot reference Name)
if (pos < fileContent.Length - searchedText.Length - 1 }
&& char.IsLetterOrDigit(fileContent, pos + searchedText.Length)) if (pos < fileContent.Length - searchedText.Length - 1
{ && char.IsLetterOrDigit(fileContent, pos + searchedText.Length))
continue; // memberName is not a whole word (a.Name2 cannot reference Name) {
continue; // memberName is not a whole word (a.Name2 cannot reference Name)
}
exprPos = pos;
} else {
exprPos = pos-1; // indexer expressions are found by resolving the part before the indexer
} }
if (expressionFinder == null) { if (expressionFinder == null) {
expressionFinder = ParserService.GetExpressionFinder(fileName); expressionFinder = ParserService.GetExpressionFinder(fileName);
} }
ExpressionResult expr = expressionFinder.FindFullExpression(fileContent, pos); ExpressionResult expr = expressionFinder.FindFullExpression(fileContent, exprPos);
if (expr.Expression != null) { if (expr.Expression != null) {
Point position = GetPosition(fileContent, pos); Point position = GetPosition(fileContent, exprPos);
repeatResolve: repeatResolve:
// TODO: Optimize by re-using the same resolver if multiple expressions were // TODO: Optimize by re-using the same resolver if multiple expressions were
// found in this file (the resolver should parse all methods at once) // found in this file (the resolver should parse all methods at once)
@ -189,18 +202,14 @@ namespace ICSharpCode.SharpDevelop.Refactoring
// find reference to local variable // find reference to local variable
if (IsReferenceToLocalVariable(rr, member)) { if (IsReferenceToLocalVariable(rr, member)) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr)); list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
} else if (FixIndexerExpression(expressionFinder, ref expr, mrr)) {
goto repeatResolve;
} }
} else if (member != null) { } else if (member != null) {
// find reference to member // find reference to member
if (IsReferenceToMember(member, rr)) { if (IsReferenceToMember(member, rr)) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr)); list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
} else if (mrr != null && mrr.ResolvedMember is IProperty && ((IProperty)mrr.ResolvedMember).IsIndexer) { } else if (FixIndexerExpression(expressionFinder, ref expr, mrr)) {
// we got an indexer call as expression ("objectList[0].ToString()[2]")
// strip the index from the expression to resolve the underlying expression
string newExpr = expressionFinder.RemoveLastPart(expr.Expression);
if (newExpr.Length >= expr.Expression.Length)
throw new ApplicationException("new expression must be shorter than old expression");
expr.Expression = newExpr;
goto repeatResolve; goto repeatResolve;
} }
} else { } else {
@ -221,6 +230,45 @@ namespace ICSharpCode.SharpDevelop.Refactoring
} }
} }
/// <summary>
/// Makes the given ExpressionResult point to the underlying expression if
/// the expression is an indexer expression.
/// </summary>
/// <returns><c>true</c>, if the expression was an indexer expression and has been changed, <c>false</c> otherwise.</returns>
public static bool FixIndexerExpression(IExpressionFinder expressionFinder, ref ExpressionResult expr, MemberResolveResult mrr)
{
if (mrr != null && mrr.ResolvedMember is IProperty && ((IProperty)mrr.ResolvedMember).IsIndexer) {
// we got an indexer call as expression ("objectList[0].ToString()[2]")
// strip the index from the expression to resolve the underlying expression
string newExpr = expressionFinder.RemoveLastPart(expr.Expression);
if (newExpr.Length >= expr.Expression.Length) {
throw new ApplicationException("new expression must be shorter than old expression");
}
expr.Expression = newExpr;
return true;
}
return false;
}
/// <summary>
/// Determines the token that denotes a possible beginning of an indexer
/// expression in the specified file.
/// </summary>
static string GetIndexerExpressionStartToken(string fileName)
{
if (fileName != null) {
ParseInformation pi = ParserService.GetParseInformation(fileName);
if (pi != null &&
pi.MostRecentCompilationUnit != null &&
pi.MostRecentCompilationUnit.ProjectContent != null &&
pi.MostRecentCompilationUnit.ProjectContent.Language != null) {
return pi.MostRecentCompilationUnit.ProjectContent.Language.IndexerExpressionStartToken;
}
}
LoggingService.Warn("RefactoringService: unable to determine the correct indexer expression start token for file '"+fileName+"'");
return LanguageProperties.CSharp.IndexerExpressionStartToken;
}
static Point GetPosition(string fileContent, int pos) static Point GetPosition(string fileContent, int pos)
{ {
int line = 1; int line = 1;

13
src/Main/Base/Project/Src/TextEditor/Commands/ClassMemberMenuBuilder.cs

@ -46,7 +46,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
&& !FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType); && !FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType);
if (method == null || !method.IsConstructor) { if (method == null || !method.IsConstructor) {
if (!FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType)) { if (!FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType) &&
!(member is IProperty && ((IProperty)member).IsIndexer)) {
cmd = new MenuCommand("${res:SharpDevelop.Refactoring.RenameCommand}", Rename); cmd = new MenuCommand("${res:SharpDevelop.Refactoring.RenameCommand}", Rename);
cmd.Tag = member; cmd.Tag = member;
list.Add(cmd); list.Add(cmd);
@ -223,7 +224,15 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
{ {
MenuCommand item = (MenuCommand)sender; MenuCommand item = (MenuCommand)sender;
IMember member = (IMember)item.Tag; IMember member = (IMember)item.Tag;
FindReferencesAndRenameHelper.ShowAsSearchResults("References to " + member.Name, RefactoringService.FindReferences(member, null)); string memberName;
if (member is IProperty && ((IProperty)member).IsIndexer) {
// The name of the default indexer is always "Indexer" in C#.
// Add the type name to clarify which indexer is referred to.
memberName = member.Name + " of " + member.DeclaringType.Name;
} else {
memberName = member.Name;
}
FindReferencesAndRenameHelper.ShowAsSearchResults("References to " + memberName, RefactoringService.FindReferences(member, null));
} }
} }
} }

Loading…
Cancel
Save