Browse Source

T4 template can now add virtual keyword to public methods.

The EnvDTE.CodeFunction.CanOverride property setter can be used to add a virtual keyword to the method definition.
The T4MVC template makes all controller methods virtual so it can override them in another generated class.
pull/28/head
Matt Ward 13 years ago
parent
commit
db2f9dbb06
  1. 2
      src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
  2. 3
      src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs
  3. 12
      src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs
  4. 15
      src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs
  5. 67
      src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs
  6. 1
      src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
  7. 14
      src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs
  8. 25
      src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs
  9. 2
      src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs
  10. 151
      src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs

2
src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj

@ -155,6 +155,7 @@
<Compile Include="Src\EnvDTE\Window.cs" /> <Compile Include="Src\EnvDTE\Window.cs" />
<Compile Include="Src\IClassKindUpdater.cs" /> <Compile Include="Src\IClassKindUpdater.cs" />
<Compile Include="Src\IDocumentNamespaceCreator.cs" /> <Compile Include="Src\IDocumentNamespaceCreator.cs" />
<Compile Include="Src\IVirtualMethodUpdater.cs" />
<Compile Include="Src\IProjectBrowserUpdater.cs" /> <Compile Include="Src\IProjectBrowserUpdater.cs" />
<Compile Include="Src\IRefactoringDocumentView.cs" /> <Compile Include="Src\IRefactoringDocumentView.cs" />
<Compile Include="Src\IFieldExtensions.cs" /> <Compile Include="Src\IFieldExtensions.cs" />
@ -222,6 +223,7 @@
<Compile Include="Src\IThreadSafePackageManagementEvents.cs" /> <Compile Include="Src\IThreadSafePackageManagementEvents.cs" />
<Compile Include="Src\ManagePackagesUserPrompts.cs" /> <Compile Include="Src\ManagePackagesUserPrompts.cs" />
<Compile Include="Src\ManagePackagesViewTitle.cs" /> <Compile Include="Src\ManagePackagesViewTitle.cs" />
<Compile Include="Src\VirtualMethodUpdater.cs" />
<Compile Include="Src\NewProjectsCreated.cs" /> <Compile Include="Src\NewProjectsCreated.cs" />
<Compile Include="Src\OpenMSBuildProjects.cs" /> <Compile Include="Src\OpenMSBuildProjects.cs" />
<Compile Include="Src\PackageActionRunner.cs" /> <Compile Include="Src\PackageActionRunner.cs" />

3
src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs

@ -26,6 +26,9 @@ namespace ICSharpCode.PackageManagement
public void MakeClassPartial() public void MakeClassPartial()
{ {
if (Class.IsPartial)
return;
OpenFileContainingClass(); OpenFileContainingClass();
int offset = GetPartialKeywordInsertOffset(); int offset = GetPartialKeywordInsertOffset();
InsertPartialKeyword(offset); InsertPartialKeyword(offset);

12
src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs

@ -9,17 +9,19 @@ namespace ICSharpCode.PackageManagement.EnvDTE
public class CodeFunction : CodeElement public class CodeFunction : CodeElement
{ {
IDocumentLoader documentLoader; IDocumentLoader documentLoader;
IVirtualMethodUpdater methodUpdater;
public CodeFunction(IMethod method) 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) : base(method)
{ {
this.Method = method; this.Method = method;
this.documentLoader = documentLoader; this.documentLoader = documentLoader;
this.methodUpdater = methodUpdater;
} }
public CodeFunction() public CodeFunction()
@ -66,7 +68,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE
public virtual bool CanOverride { public virtual bool CanOverride {
get { return Method.IsOverridable; } get { return Method.IsOverridable; }
set { throw new NotImplementedException(); } set {
if (value) {
methodUpdater.MakeMethodVirtual();
}
}
} }
public virtual vsCMFunction FunctionKind { public virtual vsCMFunction FunctionKind {

15
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
{
/// <summary>
/// Used to update a method's source code and make the method virtual.
/// </summary>
public interface IVirtualMethodUpdater
{
void MakeMethodVirtual();
}
}

67
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";
}
}
}

1
src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj

@ -186,6 +186,7 @@
<Compile Include="Src\Helpers\TestableInstallProjectTemplatePackagesCommand.cs" /> <Compile Include="Src\Helpers\TestableInstallProjectTemplatePackagesCommand.cs" />
<Compile Include="Src\Helpers\TestablePowerShellMissingConsoleHost.cs" /> <Compile Include="Src\Helpers\TestablePowerShellMissingConsoleHost.cs" />
<Compile Include="Src\InstallProjectTemplatePackagesCommandTests.cs" /> <Compile Include="Src\InstallProjectTemplatePackagesCommandTests.cs" />
<Compile Include="Src\VirtualMethodUpdaterTests.cs" />
<Compile Include="Src\NewProjectsCreatedTests.cs" /> <Compile Include="Src\NewProjectsCreatedTests.cs" />
<Compile Include="Src\PackageActionRunnerTests.cs" /> <Compile Include="Src\PackageActionRunnerTests.cs" />
<Compile Include="Src\PackageActionsToRunTests.cs" /> <Compile Include="Src\PackageActionsToRunTests.cs" />

14
src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs

@ -100,6 +100,20 @@ namespace PackageManagement.Tests
document.AssertWasCalled(doc => doc.Insert(7, "partial ")); 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<int>.Is.Anything, Arg<string>.Is.Anything));
}
[Test] [Test]
public void MakeClassPartial_PublicVisualBasicClassWithNoOtherModifiers_AddsVisualBasicPartialKeywordToClassDefinition() public void MakeClassPartial_PublicVisualBasicClassWithNoOtherModifiers_AddsVisualBasicPartialKeywordToClassDefinition()
{ {

25
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) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using ICSharpCode.PackageManagement;
using ICSharpCode.PackageManagement.EnvDTE; using ICSharpCode.PackageManagement.EnvDTE;
using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom;
using NUnit.Framework; using NUnit.Framework;
@ -15,6 +16,7 @@ namespace PackageManagement.Tests.EnvDTE
{ {
CodeFunction codeFunction; CodeFunction codeFunction;
MethodHelper helper; MethodHelper helper;
IVirtualMethodUpdater methodUpdater;
[SetUp] [SetUp]
public void Init() public void Init()
@ -36,7 +38,8 @@ namespace PackageManagement.Tests.EnvDTE
void CreateFunction() void CreateFunction()
{ {
codeFunction = new CodeFunction(helper.Method); methodUpdater = MockRepository.GenerateStub<IVirtualMethodUpdater>();
codeFunction = new CodeFunction(helper.Method, null, methodUpdater);
} }
void CreatePublicConstructor(string name) void CreatePublicConstructor(string name)
@ -373,5 +376,25 @@ namespace PackageManagement.Tests.EnvDTE
Assert.AreEqual(1, attributes.Count); Assert.AreEqual(1, attributes.Count);
Assert.AreEqual("System.ObsoleteAttribute", attribute.FullName); 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());
}
} }
} }

2
src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs

@ -69,7 +69,7 @@ namespace PackageManagement.Tests.EnvDTE
void CreateMethodEditPoint() void CreateMethodEditPoint()
{ {
var codeFunction = new CodeFunction(methodHelper.Method, documentLoader); var codeFunction = new CodeFunction(methodHelper.Method, documentLoader, null);
TextPoint startPoint = codeFunction.GetStartPoint(); TextPoint startPoint = codeFunction.GetStartPoint();
endPoint = codeFunction.GetEndPoint(); endPoint = codeFunction.GetEndPoint();
editPoint = startPoint.CreateEditPoint(); editPoint = startPoint.CreateEditPoint();

151
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<IRefactoringDocument>();
documentLoader = MockRepository.GenerateStub<IDocumentLoader>();
}
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<IRefactoringDocumentLine>();
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<int>.Is.Anything, Arg<string>.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<ApplicationException>(() => updater.MakeMethodVirtual());
}
[Test]
public void MakeMethodVirtual_NoPublicKeywordButMethodNameIncludesPublicKeyword_ExceptionIsThrown()
{
CreatePublicCSharpFunction();
CreateVirtualMethodUpdater();
SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs");
SetMethodDeclarationLine(1, "void publicmethod()");
Assert.Throws<ApplicationException>(() => 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 "));
}
}
}
Loading…
Cancel
Save