From f5d7d638ca29b6cf61150571129a91ab6f8e1562 Mon Sep 17 00:00:00 2001
From: sven-n <sven-n@users.noreply.github.com>
Date: Mon, 4 Nov 2013 19:48:19 +0100
Subject: [PATCH] Fixes for using-Refactorings

1. Extended 'Add Using' function by involving scope. New usings are
added to the inner (namespace-)scope, if it does have usings already.
2. Extended 'Remove unused import statements' function by removing and
sorting inside of scopes.
---
 .../Project/Src/DocumentNamespaceCreator.cs   |  2 +-
 .../Project/Src/ContextActions/AddUsing.cs    |  5 +-
 .../Src/MenuItemFactories/ResolveAttribute.cs |  2 +-
 .../ResolveExtensionMethod.cs                 |  2 +-
 .../CodeCompletionItemProvider.cs             |  2 +-
 .../NamespaceRefactoringService.cs            | 49 ++++++++++---------
 .../RefactoringService/RefactoringService.cs  | 10 ++--
 7 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/DocumentNamespaceCreator.cs b/src/AddIns/Misc/PackageManagement/Project/Src/DocumentNamespaceCreator.cs
index 15797f58b2..b02b6b6ee7 100644
--- a/src/AddIns/Misc/PackageManagement/Project/Src/DocumentNamespaceCreator.cs
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/DocumentNamespaceCreator.cs
@@ -20,7 +20,7 @@ namespace ICSharpCode.PackageManagement
 				IViewContent view = FileService.OpenFile(compilationUnit.FileName);
 				var textEditor = view as ITextEditorProvider;
 				IDocument document = textEditor.TextEditor.Document;
-				NamespaceRefactoringService.AddUsingDeclaration(compilationUnit, document, newNamespace, false);
+				NamespaceRefactoringService.AddUsingDeclaration(compilationUnit, document, compilationUnit.UsingScope, newNamespace, false);
 			}
 		}
 	}
diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs
index b119c4b4f6..0ceb2cd404 100644
--- a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs
+++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs
@@ -51,8 +51,9 @@ namespace SharpRefactoring.ContextActions
 			foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents())
 				SearchAllExtensionMethodsWithName(results, content, rr.CallName);
 			
+			var compilationUnit = context.CurrentParseInformation.CompilationUnit;
 			foreach (IClass c in results) {
-				yield return new RefactoringService.AddUsingAction(context.CurrentParseInformation.CompilationUnit, context.Editor, c.Namespace);
+				yield return new RefactoringService.AddUsingAction(compilationUnit, context.Editor, c.Namespace, compilationUnit.UsingScope);
 			}
 		}
 		
@@ -92,7 +93,7 @@ namespace SharpRefactoring.ContextActions
 			}
 			
 			foreach (IClass c in results) {
-				yield return new RefactoringService.AddUsingAction(unit, context.Editor, c.Namespace);
+				yield return new RefactoringService.AddUsingAction(unit, context.Editor, c.Namespace, unit.UsingScope);
 			}
 		}
 		
diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs
index 2578f994b5..694b168c76 100644
--- a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs
+++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs
@@ -73,7 +73,7 @@ namespace SharpRefactoring
 				subItem.Icon = ClassBrowserIconService.Namespace.CreateImage();
 				item.Items.Add(subItem);
 				subItem.Click += delegate {
-					NamespaceRefactoringService.AddUsingDeclaration(unit, context.Editor.Document, newNamespace, true);
+					NamespaceRefactoringService.AddUsingDeclaration(unit, context.Editor.Document, unit.UsingScope, newNamespace, true);
 					ParserService.BeginParse(context.Editor.FileName, context.Editor.Document);
 				};
 			}
diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs
index c37a3afe72..7c9b2e0271 100644
--- a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs
+++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs
@@ -51,7 +51,7 @@ namespace SharpRefactoring
 				subItem.Icon = ClassBrowserIconService.Namespace.CreateImage();
 				item.Items.Add(subItem);
 				subItem.Click += delegate {
-					NamespaceRefactoringService.AddUsingDeclaration(context.CompilationUnit, context.Editor.Document, newNamespace, true);
+					NamespaceRefactoringService.AddUsingDeclaration(context.CompilationUnit, context.Editor.Document, context.CompilationUnit.UsingScope, newNamespace, true);
 					ParserService.BeginParse(context.Editor.FileName, context.Editor.Document);
 				};
 			}
diff --git a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs
index 4483c301b2..a0650d9fcf 100644
--- a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs
+++ b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs
@@ -292,7 +292,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
 				
 				if (addUsing && nameResult != null && nameResult.CallingClass != null) {
 					var cu = nameResult.CallingClass.CompilationUnit;
-					NamespaceRefactoringService.AddUsingDeclaration(cu, document, selectedClass.Namespace, false);
+					NamespaceRefactoringService.AddUsingDeclaration(cu, document, nameResult.CallingClass.UsingScope, selectedClass.Namespace, false);
 					ParserService.BeginParse(editor.FileName, document);
 				}
 			} else {
diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs
index 2428f32675..27bd596b21 100644
--- a/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs
+++ b/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs
@@ -1,12 +1,13 @@
 // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
-using ICSharpCode.SharpDevelop.Editor;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+
 using ICSharpCode.SharpDevelop.Dom;
 using ICSharpCode.SharpDevelop.Dom.Refactoring;
+using ICSharpCode.SharpDevelop.Editor;
 
 namespace ICSharpCode.SharpDevelop.Refactoring
 {
@@ -37,39 +38,35 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			return 0;
 		}
 		
-		public static void ManageUsings(Gui.IProgressMonitor progressMonitor, string fileName, IDocument document, bool sort, bool removedUnused)
+		public static void ManageUsings(Gui.IProgressMonitor progressMonitor, string fileName, IDocument document, bool sort, bool removeUnused)
 		{
 			ParseInformation info = ParserService.ParseFile(fileName, document);
 			if (info == null) return;
-			ICompilationUnit cu = info.CompilationUnit;
-			
-			List<IUsing> newUsings = new List<IUsing>(cu.UsingScope.Usings);
+			var compilationUnit = info.CompilationUnit;
+			IEnumerable<IUsing> unusedDeclarations = removeUnused ? compilationUnit.ProjectContent.Language.RefactoringProvider.FindUnusedUsingDeclarations(Gui.DomProgressMonitor.Wrap(progressMonitor), fileName, document.Text, compilationUnit) : Enumerable.Empty<IUsing>();
+			var refactoringDocument = new RefactoringDocumentAdapter(document);
+			var codeGenerator = compilationUnit.ProjectContent.Language.CodeGenerator;
+			ManageUsingsForScope(compilationUnit.UsingScope, sort, unusedDeclarations, codeGenerator, refactoringDocument);
+		}
+		
+		private static void ManageUsingsForScope(IUsingScope usingScope, bool sort, IEnumerable<IUsing> unusedDeclarations, CodeGenerator codeGenerator, IRefactoringDocument refactoringDocument)
+		{
+			List<IUsing> newUsings = new List<IUsing>(usingScope.Usings);
 			if (sort) {
 				newUsings.Sort(CompareUsings);
 			}
 			
-			if (removedUnused) {
-				IList<IUsing> decl = cu.ProjectContent.Language.RefactoringProvider.FindUnusedUsingDeclarations(Gui.DomProgressMonitor.Wrap(progressMonitor), fileName, document.Text, cu);
-				if (decl != null && decl.Count > 0) {
-					foreach (IUsing u in decl) {
-						string ns = null;
-						for (int i = 0; i < u.Usings.Count; i++) {
-							ns = u.Usings[i];
-							if (ns == "System") break;
-						}
-						if (ns != "System") { // never remove "using System;"
-							newUsings.Remove(u);
-						}
-					}
-				}
+			unusedDeclarations.Where(u => !u.Usings.Any(usingName => usingName == "System")).ForEach(u => newUsings.Remove(u));
+
+			foreach(var childScope in usingScope.ChildScopes) {
+				ManageUsingsForScope(childScope, sort, unusedDeclarations, codeGenerator, refactoringDocument);
 			}
 			
-			// put empty line after last System namespace
 			if (sort) {
 				PutEmptyLineAfterLastSystemNamespace(newUsings);
 			}
 			
-			cu.ProjectContent.Language.CodeGenerator.ReplaceUsings(new RefactoringDocumentAdapter(document), cu.UsingScope.Usings, newUsings);
+			codeGenerator.ReplaceUsings(refactoringDocument, usingScope.Usings, newUsings);
 		}
 		
 		static void PutEmptyLineAfterLastSystemNamespace(List<IUsing> newUsings)
@@ -90,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			}
 		}
 		
-		public static void AddUsingDeclaration(ICompilationUnit cu, IDocument document, string newNamespace, bool sortExistingUsings)
+		public static void AddUsingDeclaration(ICompilationUnit cu, IDocument document, IUsingScope usingScope, string newNamespace, bool sortExistingUsings)
 		{
 			if (cu == null)
 				throw new ArgumentNullException("cu");
@@ -106,7 +103,11 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			IUsing newUsingDecl = new DefaultUsing(cu.ProjectContent);
 			newUsingDecl.Usings.Add(newNamespace);
 			
-			List<IUsing> newUsings = new List<IUsing>(cu.UsingScope.Usings);
+			while (!usingScope.Usings.Any() && usingScope.Parent != null) {
+				usingScope = usingScope.Parent;
+			}
+			
+			List<IUsing> newUsings = new List<IUsing>(usingScope.Usings);
 			if (sortExistingUsings) {
 				newUsings.Sort(CompareUsings);
 			}
@@ -124,7 +125,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			if (sortExistingUsings) {
 				PutEmptyLineAfterLastSystemNamespace(newUsings);
 			}
-			cu.ProjectContent.Language.CodeGenerator.ReplaceUsings(new RefactoringDocumentAdapter(document), cu.UsingScope.Usings, newUsings);
+			cu.ProjectContent.Language.CodeGenerator.ReplaceUsings(new RefactoringDocumentAdapter(document), usingScope.Usings, newUsings);
 		}
 	}
 }
diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs
index 9bacc5e1ba..3059539be0 100644
--- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs
+++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs
@@ -648,7 +648,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			}
 			foreach (IClass c in searchResults) {
 				string newNamespace = c.Namespace;
-				yield return new AddUsingAction(callingClass.CompilationUnit, editor, newNamespace);
+				yield return new AddUsingAction(callingClass.CompilationUnit, editor, newNamespace, callingClass.UsingScope);
 			}
 		}
 		
@@ -666,8 +666,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 			public ICompilationUnit CompilationUnit { get; private set; }
 			public ITextEditor Editor { get; private set; }
 			public string NewNamespace { get; private set; }
+			public IUsingScope UsingScope { get; private set; }
 			
-			public AddUsingAction(ICompilationUnit compilationUnit, ITextEditor editor, string newNamespace)
+			public AddUsingAction(ICompilationUnit compilationUnit, ITextEditor editor, string newNamespace, IUsingScope usingScope)
 			{
 				if (compilationUnit == null)
 					throw new ArgumentNullException("compilationUnit");
@@ -675,14 +676,17 @@ namespace ICSharpCode.SharpDevelop.Refactoring
 					throw new ArgumentNullException("editor");
 				if (newNamespace == null)
 					throw new ArgumentNullException("newNamespace");
+				if (usingScope == null)
+					throw new ArgumentNullException("usingScope");
 				this.CompilationUnit = compilationUnit;
 				this.Editor = editor;
 				this.NewNamespace = newNamespace;
+				this.UsingScope = usingScope;
 			}
 			
 			public void Execute()
 			{
-				NamespaceRefactoringService.AddUsingDeclaration(CompilationUnit, Editor.Document, NewNamespace, true);
+				NamespaceRefactoringService.AddUsingDeclaration(CompilationUnit, Editor.Document, UsingScope, NewNamespace, true);
 				ParserService.BeginParse(Editor.FileName, Editor.Document);
 			}