Browse Source

Fixed forum-7601: 'Remove unused import statements' command removes extension method's namespace

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3007 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
755c666347
  1. 25
      src/Main/Base/Project/Src/Gui/IProgressMonitor.cs
  2. 4
      src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs
  3. 4
      src/Main/Base/Project/Src/Services/RefactoringService/RefactorMenu.cs
  4. 1
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj
  5. 27
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IDomProgressMonitor.cs
  6. 6
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/ParseInformation.cs
  7. 144
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryRefactoringProvider.cs
  8. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs

25
src/Main/Base/Project/Src/Gui/IProgressMonitor.cs

@ -67,6 +67,31 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -67,6 +67,31 @@ namespace ICSharpCode.SharpDevelop.Gui
event EventHandler Cancelled;
}
public sealed class DomProgressMonitor : Dom.IDomProgressMonitor
{
IProgressMonitor monitor;
private DomProgressMonitor(IProgressMonitor monitor)
{
if (monitor == null)
throw new ArgumentNullException("monitor");
this.monitor = monitor;
}
public static Dom.IDomProgressMonitor Wrap(IProgressMonitor monitor)
{
if (monitor == null)
return null;
else
return new DomProgressMonitor(monitor);
}
public bool ShowingDialog {
get { return monitor.ShowingDialog; }
set { monitor.ShowingDialog = value; }
}
}
internal class DummyProgressMonitor : IProgressMonitor
{
int workDone;

4
src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs

@ -40,7 +40,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -40,7 +40,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
return 0;
}
public static void ManageUsings(string fileName, IDocument document, bool sort, bool removedUnused)
public static void ManageUsings(Gui.IProgressMonitor progressMonitor, string fileName, IDocument document, bool sort, bool removedUnused)
{
ParseInformation info = ParserService.ParseFile(fileName, document.TextContent);
if (info == null) return;
@ -52,7 +52,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -52,7 +52,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
}
if (removedUnused) {
IList<IUsing> decl = cu.ProjectContent.Language.RefactoringProvider.FindUnusedUsingDeclarations(fileName, document.TextContent, cu);
IList<IUsing> decl = cu.ProjectContent.Language.RefactoringProvider.FindUnusedUsingDeclarations(Gui.DomProgressMonitor.Wrap(progressMonitor), fileName, document.TextContent, cu);
if (decl != null && decl.Count > 0) {
foreach (IUsing u in decl) {
string ns = null;

4
src/Main/Base/Project/Src/Services/RefactoringService/RefactorMenu.cs

@ -103,7 +103,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -103,7 +103,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring
{
protected override void Run(TextEditorControl textEditor, RefactoringProvider provider)
{
NamespaceRefactoringService.ManageUsings(textEditor.FileName, textEditor.Document, true, true);
using (var pm = Gui.AsynchronousWaitDialog.ShowWaitDialog("${res:SharpDevelop.Refactoring.RemoveUnusedImports}")) {
NamespaceRefactoringService.ManageUsings(pm, textEditor.FileName, textEditor.Document, true, true);
}
}
}

1
src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj

@ -95,6 +95,7 @@ @@ -95,6 +95,7 @@
<Compile Include="Src\Implementations\SearchClassReturnType.cs" />
<Compile Include="Src\Implementations\SystemTypes.cs" />
<Compile Include="Src\Interfaces\ExplicitInterfaceImplementation.cs" />
<Compile Include="Src\Interfaces\IDomProgressMonitor.cs" />
<Compile Include="Src\Interfaces\IFreezable.cs" />
<Compile Include="Src\LazyList.cs" />
<Compile Include="Src\NRefactoryResolver\CSharpToVBNetConvertVisitor.cs" />

27
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IDomProgressMonitor.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.SharpDevelop.Dom
{
/// <summary>
/// This is a basic interface to a "progress bar" type of
/// control.
/// </summary>
public interface IDomProgressMonitor
{
/// <summary>
/// Gets/sets if the task current shows a modal dialog. Set this property to true to make progress
/// dialogs windows temporarily invisible while your modal dialog is showing.
/// </summary>
bool ShowingDialog {
get;
set;
}
}
}

6
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/ParseInformation.cs

@ -16,6 +16,12 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -16,6 +16,12 @@ namespace ICSharpCode.SharpDevelop.Dom
public ICompilationUnit BestCompilationUnit { get; private set; }
public ICompilationUnit MostRecentCompilationUnit { get; private set; }
public ParseInformation() {}
public ParseInformation(ICompilationUnit c)
{
SetCompilationUnit(c);
}
/// <summary>
/// Uses the specified compilation unit.
/// If the compilation unit is valid (ErrorsDuringCompile=false), it is used as ValidCompilationUnit,

144
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryRefactoringProvider.cs

@ -38,17 +38,21 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -38,17 +38,21 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
return false;
}
static void ShowSourceCodeErrors(string errors)
static void ShowSourceCodeErrors(IDomProgressMonitor progressMonitor, string errors)
{
if (progressMonitor != null)
progressMonitor.ShowingDialog = true;
HostCallback.ShowMessage("${res:SharpDevelop.Refactoring.CannotPerformOperationBecauseOfSyntaxErrors}\n" + errors);
if (progressMonitor != null)
progressMonitor.ShowingDialog = false;
}
NR.IParser ParseFile(string fileContent)
NR.IParser ParseFile(IDomProgressMonitor progressMonitor, string fileContent)
{
NR.IParser parser = NR.ParserFactory.CreateParser(language, new StringReader(fileContent));
parser.Parse();
if (parser.Errors.Count > 0) {
ShowSourceCodeErrors(parser.Errors.ErrorOutput);
ShowSourceCodeErrors(progressMonitor, parser.Errors.ErrorOutput);
parser.Dispose();
return null;
} else {
@ -60,66 +64,129 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -60,66 +64,129 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
protected class PossibleTypeReference
{
public string Name;
public bool Global;
public int TypeParameterCount;
public IMethod ExtensionMethod;
public PossibleTypeReference(string name)
{
this.Name = name;
}
public PossibleTypeReference(IdentifierExpression identifierExpression)
{
this.Name = identifierExpression.Identifier;
this.TypeParameterCount = identifierExpression.TypeArguments.Count;
}
public PossibleTypeReference(TypeReference tr)
{
this.Name = tr.SystemType;
this.Global = tr.IsGlobal;
this.TypeParameterCount = tr.GenericTypes.Count;
}
public PossibleTypeReference(IMethod extensionMethod)
{
this.ExtensionMethod = extensionMethod;
}
public override int GetHashCode()
{
return Name.GetHashCode() ^ Global.GetHashCode() ^ TypeParameterCount.GetHashCode();
int hashCode = 0;
unchecked {
if (Name != null) hashCode += 1000000007 * Name.GetHashCode();
hashCode += 1000000009 * TypeParameterCount.GetHashCode();
if (ExtensionMethod != null) hashCode += 1000000021 * ExtensionMethod.GetHashCode();
}
return hashCode;
}
public override bool Equals(object obj)
{
if (!(obj is PossibleTypeReference)) return false;
if (this == obj) return true;
PossibleTypeReference myPossibleTypeReference = (PossibleTypeReference)obj;
return this.Name == myPossibleTypeReference.Name && this.Global == myPossibleTypeReference.Global && this.TypeParameterCount == myPossibleTypeReference.TypeParameterCount;
PossibleTypeReference other = obj as PossibleTypeReference;
if (other == null) return false;
return this.Name == other.Name && this.TypeParameterCount == other.TypeParameterCount && object.Equals(this.ExtensionMethod, other.ExtensionMethod);
}
}
private class FindPossibleTypeReferencesVisitor : NR.Visitors.AbstractAstVisitor
{
internal Dictionary<PossibleTypeReference, object> list = new Dictionary<PossibleTypeReference, object>();
internal HashSet<PossibleTypeReference> list = new HashSet<PossibleTypeReference>();
NRefactoryResolver.NRefactoryResolver resolver;
ParseInformation parseInformation;
public FindPossibleTypeReferencesVisitor(ParseInformation parseInformation)
{
if (parseInformation != null) {
this.parseInformation = parseInformation;
resolver = new NRefactoryResolver.NRefactoryResolver(parseInformation.MostRecentCompilationUnit.ProjectContent.Language);
}
}
public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
{
list[new PossibleTypeReference(identifierExpression.Identifier)] = data;
list.Add(new PossibleTypeReference(identifierExpression));
return base.VisitIdentifierExpression(identifierExpression, data);
}
public override object VisitTypeReference(TypeReference typeReference, object data)
{
list[new PossibleTypeReference(typeReference)] = data;
if (!typeReference.IsGlobal) {
list.Add(new PossibleTypeReference(typeReference));
}
return base.VisitTypeReference(typeReference, data);
}
public override object VisitAttribute(ICSharpCode.NRefactory.Ast.Attribute attribute, object data)
{
list[new PossibleTypeReference(attribute.Name)] = data;
list[new PossibleTypeReference(attribute.Name + "Attribute")] = data;
list.Add(new PossibleTypeReference(attribute.Name));
list.Add(new PossibleTypeReference(attribute.Name + "Attribute"));
return base.VisitAttribute(attribute, data);
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
base.VisitInvocationExpression(invocationExpression, data);
if (invocationExpression.TargetObject is MemberReferenceExpression) {
MemberResolveResult mrr = resolver.ResolveInternal(invocationExpression, ExpressionContext.Default) as MemberResolveResult;
if (mrr != null) {
IMethod method = mrr.ResolvedMember as IMethod;
if (method != null && method.IsExtensionMethod) {
list.Add(new PossibleTypeReference(method));
}
}
}
return null;
}
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
// Initialize resolver for method:
if (!methodDeclaration.Body.IsNull && resolver != null) {
if (resolver.Initialize(parseInformation, methodDeclaration.Body.StartLocation.Y, methodDeclaration.Body.StartLocation.X)) {
resolver.RunLookupTableVisitor(methodDeclaration);
}
}
return base.VisitMethodDeclaration(methodDeclaration, data);
}
public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
{
if (resolver != null) {
if (resolver.Initialize(parseInformation, propertyDeclaration.BodyStart.Y, propertyDeclaration.BodyStart.X)) {
resolver.RunLookupTableVisitor(propertyDeclaration);
}
}
return base.VisitPropertyDeclaration(propertyDeclaration, data);
}
}
protected virtual Dictionary<PossibleTypeReference, object> FindPossibleTypeReferences(string fileContent)
protected virtual HashSet<PossibleTypeReference> FindPossibleTypeReferences(IDomProgressMonitor progressMonitor, string fileContent, ParseInformation parseInfo)
{
NR.IParser parser = ParseFile(fileContent);
NR.IParser parser = ParseFile(progressMonitor, fileContent);
if (parser == null) {
return null;
} else {
FindPossibleTypeReferencesVisitor visitor = new FindPossibleTypeReferencesVisitor();
FindPossibleTypeReferencesVisitor visitor = new FindPossibleTypeReferencesVisitor(parseInfo);
parser.CompilationUnit.AcceptVisitor(visitor, null);
parser.Dispose();
return visitor.list;
@ -132,36 +199,49 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -132,36 +199,49 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
}
}
public override IList<IUsing> FindUnusedUsingDeclarations(string fileName, string fileContent, ICompilationUnit cu)
public override IList<IUsing> FindUnusedUsingDeclarations(IDomProgressMonitor progressMonitor, string fileName, string fileContent, ICompilationUnit cu)
{
IClass @class = cu.Classes.Count == 0 ? null : cu.Classes[0];
Dictionary<PossibleTypeReference, object> references = FindPossibleTypeReferences(fileContent);
HashSet<PossibleTypeReference> references = FindPossibleTypeReferences(progressMonitor, fileContent, new ParseInformation(cu));
if (references == null) return new IUsing[0];
Dictionary<IUsing, object> dict = new Dictionary<IUsing, object>();
foreach (PossibleTypeReference tr in references.Keys) {
SearchTypeRequest request = new SearchTypeRequest(tr.Name, tr.TypeParameterCount, @class, cu, 1, 1);
SearchTypeResult response = cu.ProjectContent.SearchType(request);
if (response.UsedUsing != null) {
dict[response.UsedUsing] = null;
HashSet<IUsing> usedUsings = new HashSet<IUsing>();
foreach (PossibleTypeReference tr in references) {
if (tr.ExtensionMethod != null) {
// the invocation of an extension method can implicitly use a using
StringComparer nameComparer = cu.ProjectContent.Language.NameComparer;
foreach (IUsing import in cu.Usings) {
foreach (string i in import.Usings) {
if (nameComparer.Equals(tr.ExtensionMethod.DeclaringType.Namespace, i)) {
usedUsings.Add(import);
}
}
}
} else {
// normal possible type reference
SearchTypeRequest request = new SearchTypeRequest(tr.Name, tr.TypeParameterCount, @class, cu, 1, 1);
SearchTypeResult response = cu.ProjectContent.SearchType(request);
if (response.UsedUsing != null) {
usedUsings.Add(response.UsedUsing);
}
}
}
List<IUsing> list = new List<IUsing>();
List<IUsing> unusedUsings = new List<IUsing>();
foreach (IUsing import in cu.Usings) {
if (!dict.ContainsKey(import)) {
if (!usedUsings.Contains(import)) {
if (import.HasAliases) {
foreach (string key in import.Aliases.Keys) {
if (references.ContainsKey(new PossibleTypeReference(key)))
if (references.Contains(new PossibleTypeReference(key)))
goto checkNextImport;
}
}
list.Add(import); // this using is unused
unusedUsings.Add(import); // this using is unused
}
checkNextImport:;
}
return list;
return unusedUsings;
}
#endregion
@ -174,7 +254,7 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -174,7 +254,7 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
public override string CreateNewFileLikeExisting(string existingFileContent, string codeForNewType)
{
NR.IParser parser = ParseFile(existingFileContent);
NR.IParser parser = ParseFile(null, existingFileContent);
if (parser == null) {
return null;
}

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -35,7 +35,7 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
}
}
public virtual IList<IUsing> FindUnusedUsingDeclarations(string fileName, string fileContent, ICompilationUnit compilationUnit)
public virtual IList<IUsing> FindUnusedUsingDeclarations(IDomProgressMonitor progressMonitor, string fileName, string fileContent, ICompilationUnit compilationUnit)
{
throw new NotSupportedException();
}

Loading…
Cancel
Save