diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
index ff3c471fd3..8fc60c7231 100644
--- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
+++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
@@ -155,6 +155,7 @@
+
@@ -222,6 +223,7 @@
+
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs
index 003690bf3a..e355235cc7 100644
--- a/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs
@@ -26,6 +26,9 @@ namespace ICSharpCode.PackageManagement
public void MakeClassPartial()
{
+ if (Class.IsPartial)
+ return;
+
OpenFileContainingClass();
int offset = GetPartialKeywordInsertOffset();
InsertPartialKeyword(offset);
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs
index 5e95b16e1b..b1afbed8d1 100644
--- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs
@@ -9,17 +9,19 @@ namespace ICSharpCode.PackageManagement.EnvDTE
public class CodeFunction : CodeElement
{
IDocumentLoader documentLoader;
+ IVirtualMethodUpdater methodUpdater;
public CodeFunction(IMethod method)
- : this(method, new DocumentLoader())
+ : this(method, new DocumentLoader(), new VirtualMethodUpdater(method))
{
}
- public CodeFunction(IMethod method, IDocumentLoader documentLoader)
+ public CodeFunction(IMethod method, IDocumentLoader documentLoader, IVirtualMethodUpdater methodUpdater)
: base(method)
{
this.Method = method;
this.documentLoader = documentLoader;
+ this.methodUpdater = methodUpdater;
}
public CodeFunction()
@@ -66,7 +68,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE
public virtual bool CanOverride {
get { return Method.IsOverridable; }
- set { throw new NotImplementedException(); }
+ set {
+ if (value) {
+ methodUpdater.MakeMethodVirtual();
+ }
+ }
}
public virtual vsCMFunction FunctionKind {
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs
new file mode 100644
index 0000000000..1333a789ca
--- /dev/null
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs
@@ -0,0 +1,15 @@
+// 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 System;
+
+namespace ICSharpCode.PackageManagement
+{
+ ///
+ /// Used to update a method's source code and make the method virtual.
+ ///
+ public interface IVirtualMethodUpdater
+ {
+ void MakeMethodVirtual();
+ }
+}
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs
new file mode 100644
index 0000000000..37daf016e1
--- /dev/null
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs
@@ -0,0 +1,67 @@
+// 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 System;
+using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Dom.Refactoring;
+
+namespace ICSharpCode.PackageManagement
+{
+ public class VirtualMethodUpdater : IVirtualMethodUpdater
+ {
+ public VirtualMethodUpdater(IMethod method)
+ : this(method, new DocumentLoader())
+ {
+ }
+
+ public VirtualMethodUpdater(IMethod method, IDocumentLoader documentLoader)
+ {
+ this.Method = method;
+ this.DocumentLoader = documentLoader;
+ }
+
+ IMethod Method { get; set; }
+ IDocumentLoader DocumentLoader { get; set; }
+ IRefactoringDocument Document { get; set; }
+
+ public void MakeMethodVirtual()
+ {
+ if (Method.IsVirtual)
+ return;
+
+ OpenFileContainingMethod();
+ int offset = GetVirtualKeywordInsertOffset();
+ InsertVirtualKeyword(offset);
+ }
+
+ void OpenFileContainingMethod()
+ {
+ Document = DocumentLoader.LoadRefactoringDocument(Method.CompilationUnit.FileName);
+ }
+
+ int GetVirtualKeywordInsertOffset()
+ {
+ IRefactoringDocumentLine line = Document.GetLine(Method.Region.BeginLine);
+ int offset = line.Text.IndexOf("public ", StringComparison.OrdinalIgnoreCase);
+ if (offset >= 0) {
+ int publicKeywordLength = 6;
+ return offset + line.Offset + publicKeywordLength + 1;
+ }
+ throw new ApplicationException("Unable to find 'method' declaration.");
+ }
+
+ void InsertVirtualKeyword(int offset)
+ {
+ string virtualKeyword = GetLanguageSpecificVirtualKeyword();
+ Document.Insert(offset, virtualKeyword + " ");
+ }
+
+ string GetLanguageSpecificVirtualKeyword()
+ {
+ if (Method.ProjectContent.Language == LanguageProperties.VBNet) {
+ return "Overridable";
+ }
+ return "virtual";
+ }
+ }
+}
diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
index 1c5b6579af..750344421d 100644
--- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
+++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
@@ -186,6 +186,7 @@
+
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs
index 3490cbf352..54a92eeb0b 100644
--- a/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs
+++ b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs
@@ -100,6 +100,20 @@ namespace PackageManagement.Tests
document.AssertWasCalled(doc => doc.Insert(7, "partial "));
}
+ [Test]
+ public void MakeClassPartial_PublicCSharpClassThatIsAlreadyPartial_ClassDefinitionIsUnchanged()
+ {
+ CreatePublicCSharpClass();
+ CreateClassKindUpdater();
+ classHelper.MakeClassPartial();
+ SetClassFileName(@"d:\projects\MyProject\MyClass.cs");
+ SetClassDeclarationLine(1, "public class MyClass");
+
+ updater.MakeClassPartial();
+
+ document.AssertWasNotCalled(doc => doc.Insert(Arg.Is.Anything, Arg.Is.Anything));
+ }
+
[Test]
public void MakeClassPartial_PublicVisualBasicClassWithNoOtherModifiers_AddsVisualBasicPartialKeywordToClassDefinition()
{
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs
index 215e7827c1..8fcd19c0cd 100644
--- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs
+++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs
@@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
+using ICSharpCode.PackageManagement;
using ICSharpCode.PackageManagement.EnvDTE;
using ICSharpCode.SharpDevelop.Dom;
using NUnit.Framework;
@@ -15,6 +16,7 @@ namespace PackageManagement.Tests.EnvDTE
{
CodeFunction codeFunction;
MethodHelper helper;
+ IVirtualMethodUpdater methodUpdater;
[SetUp]
public void Init()
@@ -36,7 +38,8 @@ namespace PackageManagement.Tests.EnvDTE
void CreateFunction()
{
- codeFunction = new CodeFunction(helper.Method);
+ methodUpdater = MockRepository.GenerateStub();
+ codeFunction = new CodeFunction(helper.Method, null, methodUpdater);
}
void CreatePublicConstructor(string name)
@@ -373,5 +376,25 @@ namespace PackageManagement.Tests.EnvDTE
Assert.AreEqual(1, attributes.Count);
Assert.AreEqual("System.ObsoleteAttribute", attribute.FullName);
}
+
+ [Test]
+ public void CanOverride_SetToTrueForFunction_VirtualKeywordAddedToFunction()
+ {
+ CreatePublicFunction("MyClass.MyFunction");
+
+ codeFunction.CanOverride = true;
+
+ methodUpdater.AssertWasCalled(updater => updater.MakeMethodVirtual());
+ }
+
+ [Test]
+ public void CanOverride_SetToFalseForFunction_VirtualKeywordNotAddedToFunction()
+ {
+ CreatePublicFunction("MyClass.MyFunction");
+
+ codeFunction.CanOverride = false;
+
+ methodUpdater.AssertWasNotCalled(updater => updater.MakeMethodVirtual());
+ }
}
}
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs
index 83a02b3348..1cf28aa08b 100644
--- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs
+++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs
@@ -69,7 +69,7 @@ namespace PackageManagement.Tests.EnvDTE
void CreateMethodEditPoint()
{
- var codeFunction = new CodeFunction(methodHelper.Method, documentLoader);
+ var codeFunction = new CodeFunction(methodHelper.Method, documentLoader, null);
TextPoint startPoint = codeFunction.GetStartPoint();
endPoint = codeFunction.GetEndPoint();
editPoint = startPoint.CreateEditPoint();
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs
new file mode 100644
index 0000000000..01c222887e
--- /dev/null
+++ b/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs
@@ -0,0 +1,151 @@
+// 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 System;
+using ICSharpCode.PackageManagement;
+using ICSharpCode.SharpDevelop.Dom.Refactoring;
+using NUnit.Framework;
+using PackageManagement.Tests.Helpers;
+using Rhino.Mocks;
+
+namespace PackageManagement.Tests
+{
+ [TestFixture]
+ public class VirtualMethodUpdaterTests
+ {
+ VirtualMethodUpdater updater;
+ MethodHelper methodHelper;
+ IRefactoringDocument document;
+ IDocumentLoader documentLoader;
+
+ [SetUp]
+ public void Init()
+ {
+ methodHelper = new MethodHelper();
+ document = MockRepository.GenerateStub();
+ documentLoader = MockRepository.GenerateStub();
+ }
+
+ void CreatePublicCSharpFunction()
+ {
+ methodHelper.CreatePublicMethod("MyMethod");
+ methodHelper.ProjectContentHelper.ProjectContentIsForCSharpProject();
+ }
+
+ void CreatePublicVisualBasicFunction()
+ {
+ methodHelper.CreatePublicMethod("MyMethod");
+ methodHelper.ProjectContentHelper.ProjectContentIsForVisualBasicProject();
+ }
+
+ void SetDocumentFileName(string fileName)
+ {
+ documentLoader.Stub(loader => loader.LoadRefactoringDocument(fileName)).Return(document);
+ }
+
+ void CreateVirtualMethodUpdater()
+ {
+ updater = new VirtualMethodUpdater(methodHelper.Method, documentLoader);
+ }
+
+ void SetFileNameForMethod(string fileName)
+ {
+ methodHelper.SetCompilationUnitFileName(fileName);
+ SetDocumentFileName(fileName);
+ }
+
+ void SetMethodDeclarationLineWithOffset(int line, string text, int offset)
+ {
+ methodHelper.FunctionStartsAtLine(line);
+ SetDocumentLineText(line, text, offset);
+ }
+
+ void SetMethodDeclarationLine(int line, string text)
+ {
+ SetMethodDeclarationLineWithOffset(line, text, 0);
+ }
+
+ void SetDocumentLineText(int lineNumber, string text, int offset)
+ {
+ IRefactoringDocumentLine documentLine = MockRepository.GenerateStub();
+ documentLine.Stub(line => line.Text).Return(text);
+ documentLine.Stub(line => line.Offset).Return(offset);
+ document.Stub(doc => doc.GetLine(lineNumber)).Return(documentLine);
+ }
+
+ [Test]
+ public void MakeMethodVirtual_PublicCSharpClassWithNoOtherModifiers_AddsVirtualKeywordToMethodDefinition()
+ {
+ CreatePublicCSharpFunction();
+ CreateVirtualMethodUpdater();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
+ SetMethodDeclarationLine(1, "public void MyMethod()");
+
+ updater.MakeMethodVirtual();
+
+ document.AssertWasCalled(doc => doc.Insert(7, "virtual "));
+ }
+
+ [Test]
+ public void MakeMethodVirtual_MethodAlreadyVirtual_MethodDefinitionIsNotChanged()
+ {
+ CreatePublicCSharpFunction();
+ CreateVirtualMethodUpdater();
+ methodHelper.MakeMethodVirtual();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
+ SetMethodDeclarationLine(1, "public void MyMethod()");
+
+ updater.MakeMethodVirtual();
+
+ document.AssertWasNotCalled(doc => doc.Insert(Arg.Is.Anything, Arg.Is.Anything));
+ }
+
+ [Test]
+ public void MakeMethodVirtual_PublicVisualBasicClassWithNoOtherModifiers_AddsOverridableKeywordToMethodDefinition()
+ {
+ CreatePublicVisualBasicFunction();
+ CreateVirtualMethodUpdater();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.vb");
+ SetMethodDeclarationLine(1, "Public Sub MyMethod");
+
+ updater.MakeMethodVirtual();
+
+ document.AssertWasCalled(doc => doc.Insert(7, "Overridable "));
+ }
+
+ [Test]
+ public void MakeMethodVirtual_NoPublicKeywordInClassDeclarationLine_ExceptionIsThrown()
+ {
+ CreatePublicCSharpFunction();
+ CreateVirtualMethodUpdater();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
+ SetMethodDeclarationLine(1, "void test()");
+
+ Assert.Throws(() => updater.MakeMethodVirtual());
+ }
+
+ [Test]
+ public void MakeMethodVirtual_NoPublicKeywordButMethodNameIncludesPublicKeyword_ExceptionIsThrown()
+ {
+ CreatePublicCSharpFunction();
+ CreateVirtualMethodUpdater();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
+ SetMethodDeclarationLine(1, "void publicmethod()");
+
+ Assert.Throws(() => updater.MakeMethodVirtual());
+ }
+
+ [Test]
+ public void MakeMethodVirtual_PublicCSharpMethodNotOnFirstLine_AddsVirtualKeywordToMethodDefinitionAtCorrectOffset()
+ {
+ CreatePublicCSharpFunction();
+ CreateVirtualMethodUpdater();
+ SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
+ SetMethodDeclarationLineWithOffset(1, "public void MyMethod()", offset: 10);
+
+ updater.MakeMethodVirtual();
+
+ document.AssertWasCalled(doc => doc.Insert(17, "virtual "));
+ }
+ }
+}