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 @@ -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)
{
return true;
@ -187,6 +196,12 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -187,6 +196,12 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public override string IndexerExpressionStartToken {
get {
return "(";
}
}
public override bool ShowInNamespaceCompletion(IClass c)
{
foreach (IAttribute attr in c.Attributes) {

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

@ -67,22 +67,35 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -67,22 +67,35 @@ namespace ICSharpCode.SharpDevelop.Refactoring
}
// 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;
if (rr is MethodResolveResult) {
item = MakeItem(definitions, ((MethodResolveResult)rr).GetMethodIfSingleOverload());
} 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) {
item = MakeItem(definitions, ((TypeResolveResult)rr).ResolvedClass);
} else if (rr is LocalResolveResult) {
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 (rr is LocalResolveResult)
resultItems.Insert(0, item);
else
resultItems.Add(item);
resultItems.Insert(insertIndex, item);
}
// Include menu for current class and method
@ -200,16 +213,19 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -200,16 +213,19 @@ namespace ICSharpCode.SharpDevelop.Refactoring
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) {
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;
}

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

@ -149,6 +149,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -149,6 +149,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
{
string lowerFileContent = fileContent.ToLower();
string searchedText; // the text that is searched for
bool searchingIndexer = false;
if (member == null) {
searchedText = parentClass.Name.ToLower();
@ -158,28 +159,40 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -158,28 +159,40 @@ namespace ICSharpCode.SharpDevelop.Refactoring
// (examples: derived classes, partial classes)
if (member is IMethod && ((IMethod)member).IsConstructor)
searchedText = parentClass.Name.ToLower();
else
searchedText = member.Name.ToLower();
else {
if (member is IProperty && ((IProperty)member).IsIndexer) {
searchingIndexer = true;
searchedText = GetIndexerExpressionStartToken(fileName);
} else {
searchedText = member.Name.ToLower();
}
}
}
int pos = -1;
int exprPos;
IExpressionFinder expressionFinder = null;
while ((pos = lowerFileContent.IndexOf(searchedText, pos + 1)) >= 0) {
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))
{
continue; // memberName is not a whole word (a.Name2 cannot reference Name)
if (!searchingIndexer) {
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))
{
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) {
expressionFinder = ParserService.GetExpressionFinder(fileName);
}
ExpressionResult expr = expressionFinder.FindFullExpression(fileContent, pos);
ExpressionResult expr = expressionFinder.FindFullExpression(fileContent, exprPos);
if (expr.Expression != null) {
Point position = GetPosition(fileContent, pos);
Point position = GetPosition(fileContent, exprPos);
repeatResolve:
// TODO: Optimize by re-using the same resolver if multiple expressions were
// found in this file (the resolver should parse all methods at once)
@ -189,18 +202,14 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -189,18 +202,14 @@ namespace ICSharpCode.SharpDevelop.Refactoring
// find reference to local variable
if (IsReferenceToLocalVariable(rr, member)) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
} else if (FixIndexerExpression(expressionFinder, ref expr, mrr)) {
goto repeatResolve;
}
} else if (member != null) {
// find reference to member
if (IsReferenceToMember(member, rr)) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
} else 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;
} else if (FixIndexerExpression(expressionFinder, ref expr, mrr)) {
goto repeatResolve;
}
} else {
@ -221,6 +230,45 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -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)
{
int line = 1;

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

@ -46,7 +46,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands @@ -46,7 +46,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
&& !FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType);
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.Tag = member;
list.Add(cmd);
@ -223,7 +224,15 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands @@ -223,7 +224,15 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
{
MenuCommand item = (MenuCommand)sender;
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