📄 refactoringservice.cs
字号:
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 1393 $</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Refactoring
{
public static class RefactoringService
{
#region FindDerivedClasses
/// <summary>
/// Finds all classes deriving from baseClass.
/// </summary>
/// <param name="baseClass">The base class.</param>
/// <param name="projectContents">The project contents in which derived classes should be searched.</param>
/// <param name="directDerivationOnly">If true, gets only the classes that derive directly from <paramref name="baseClass"/>.</param>
public static List<IClass> FindDerivedClasses(IClass baseClass, IEnumerable<IProjectContent> projectContents, bool directDerivationOnly)
{
baseClass = baseClass.GetCompoundClass();
string baseClassName = baseClass.Name;
string baseClassFullName = baseClass.FullyQualifiedName;
List<IClass> list = new List<IClass>();
foreach (IProjectContent pc in projectContents) {
if (pc != baseClass.ProjectContent && !pc.ReferencedContents.Contains(baseClass.ProjectContent)) {
// only project contents referencing the content of the base class
// can derive from the class
continue;
}
AddDerivedClasses(pc, baseClass, baseClassName, baseClassFullName, pc.Classes, list);
}
if (!directDerivationOnly) {
List<IClass> additional = new List<IClass>();
foreach (IClass c in list) {
additional.AddRange(FindDerivedClasses(c, projectContents, directDerivationOnly));
}
foreach (IClass c in additional) {
if (!list.Contains(c))
list.Add(c);
}
}
return list;
}
static void AddDerivedClasses(IProjectContent pc, IClass baseClass, string baseClassName, string baseClassFullName,
IEnumerable<IClass> classList, IList<IClass> resultList)
{
foreach (IClass c in classList) {
AddDerivedClasses(pc, baseClass, baseClassName, baseClassFullName, c.InnerClasses, resultList);
int count = c.BaseTypes.Count;
for (int i = 0; i < count; i++) {
string baseTypeName = c.BaseTypes[i].Name;
if (pc.Language.NameComparer.Equals(baseTypeName, baseClassName) ||
pc.Language.NameComparer.Equals(baseTypeName, baseClassFullName)) {
IReturnType possibleBaseClass = c.GetBaseType(i);
if (possibleBaseClass.FullyQualifiedName == baseClass.FullyQualifiedName) {
resultList.Add(c);
}
}
}
}
}
#endregion
#region FindReferences
/// <summary>
/// Find all references to the specified member.
/// </summary>
public static List<Reference> FindReferences(IMember member, IProgressMonitor progressMonitor)
{
return RunFindReferences(member.DeclaringType, member, false, progressMonitor);
}
/// <summary>
/// Find all references to the specified class.
/// </summary>
public static List<Reference> FindReferences(IClass @class, IProgressMonitor progressMonitor)
{
if (@class == null)
throw new ArgumentNullException("class");
return RunFindReferences(@class, null, false, progressMonitor);
}
/// <summary>
/// Find all references to the resolved entity.
/// </summary>
public static List<Reference> FindReferences(ResolveResult entity, IProgressMonitor progressMonitor)
{
if (entity == null)
throw new ArgumentNullException("entity");
if (entity is LocalResolveResult) {
return RunFindReferences(entity.CallingClass, (entity as LocalResolveResult).Field, true, progressMonitor);
} else if (entity is TypeResolveResult) {
return FindReferences((entity as TypeResolveResult).ResolvedClass, progressMonitor);
} else if (entity is MemberResolveResult) {
return FindReferences((entity as MemberResolveResult).ResolvedMember, progressMonitor);
} else if (entity is MethodResolveResult) {
IMethod method = (entity as MethodResolveResult).GetMethodIfSingleOverload();
if (method != null) {
return FindReferences(method, progressMonitor);
}
} else if (entity is MixedResolveResult) {
return FindReferences((entity as MixedResolveResult).PrimaryResult, progressMonitor);
}
return null;
}
/// <summary>
/// Find all references to the specified local variable.
/// </summary>
public static List<Reference> FindReferences(LocalResolveResult local, IProgressMonitor progressMonitor)
{
return RunFindReferences(local.CallingClass, local.Field, true, progressMonitor);
}
/// <summary>
/// This method can be used in three modes:
/// 1. Find references to classes (parentClass = targetClass, member = null, isLocal = false)
/// 2. Find references to members (parentClass = parent, member = member, isLocal = false)
/// 3. Find references to local variables (parentClass = parent, member = local var as field, isLocal = true)
/// </summary>
static List<Reference> RunFindReferences(IClass ownerClass, IMember member,
bool isLocal,
IProgressMonitor progressMonitor)
{
if (ParserService.LoadSolutionProjectsThreadRunning) {
MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}");
return null;
}
List<ProjectItem> files;
if (isLocal) {
files = new List<ProjectItem>();
files.Add(FindItem(ownerClass.CompilationUnit.FileName));
} else {
ownerClass = ownerClass.GetCompoundClass();
files = GetPossibleFiles(ownerClass, member);
}
ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(files.ToArray());
List<Reference> references = new List<Reference>();
try {
if (progressMonitor != null) {
progressMonitor.BeginTask("${res:SharpDevelop.Refactoring.FindingReferences}", files.Count);
}
#if DEBUG
if (System.Windows.Forms.Control.ModifierKeys == System.Windows.Forms.Keys.Control) {
System.Diagnostics.Debugger.Break();
}
#endif
while (enumerator.MoveNext()) {
if (progressMonitor != null) {
progressMonitor.WorkDone = enumerator.Index;
}
AddReferences(references, ownerClass, member, isLocal, enumerator.CurrentFileName, enumerator.CurrentFileContent);
}
} finally {
if (progressMonitor != null) {
progressMonitor.Done();
}
enumerator.Dispose();
}
return references;
}
/// <summary>
/// This method can be used in three modes (like RunFindReferences)
/// </summary>
static void AddReferences(List<Reference> list,
IClass parentClass, IMember member,
bool isLocal,
string fileName, string fileContent)
{
string lowerFileContent = fileContent.ToLowerInvariant();
string searchedText; // the text that is searched for
bool searchingIndexer = false;
if (member == null) {
searchedText = parentClass.Name.ToLowerInvariant();
} else {
// When looking for a member, the name of the parent class does not always exist
// in the file where the member is accessed.
// (examples: derived classes, partial classes)
if (member is IMethod && ((IMethod)member).IsConstructor)
searchedText = parentClass.Name.ToLowerInvariant();
else {
if (member is IProperty && ((IProperty)member).IsIndexer) {
searchingIndexer = true;
searchedText = GetIndexerExpressionStartToken(fileName);
} else {
searchedText = member.Name.ToLowerInvariant();
}
}
}
int pos = -1;
int exprPos;
IExpressionFinder expressionFinder = null;
while ((pos = lowerFileContent.IndexOf(searchedText, pos + 1)) >= 0) {
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, exprPos);
if (expr.Expression != null) {
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)
ResolveResult rr = ParserService.Resolve(expr, position.Y, position.X, fileName, fileContent);
MemberResolveResult mrr = rr as MemberResolveResult;
if (isLocal) {
// 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 (FixIndexerExpression(expressionFinder, ref expr, mrr)) {
goto repeatResolve;
}
} else {
// find reference to class
if (mrr != null) {
if (mrr.ResolvedMember is IMethod && ((IMethod)mrr.ResolvedMember).IsConstructor) {
if (mrr.ResolvedMember.DeclaringType.FullyQualifiedName == parentClass.FullyQualifiedName) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
}
}
} else {
if (rr is TypeResolveResult && rr.ResolvedType.FullyQualifiedName == parentClass.FullyQualifiedName) {
list.Add(new Reference(fileName, pos, searchedText.Length, expr.Expression, rr));
}
}
}
}
}
}
/// <summary>
/// Makes the given ExpressionResult point to the underlying expression if
/// the expression is an indexer expression.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -