Browse Source

T4 template can now add partial keyword to class.

The EnvDTE.CodeClass2.ClassKind property setter can be used to add a partial keyword to the class definition.
The T4MVC template makes all controller classes partial so it can add extend the original class with an associated partial controller class that it generates.
pull/28/head
Matt Ward 13 years ago
parent
commit
d7b7ee5247
  1. 2
      src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
  2. 63
      src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs
  3. 18
      src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs
  4. 12
      src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs
  5. 1
      src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
  6. 151
      src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs
  7. 25
      src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs
  8. 10
      src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs

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

@ -74,6 +74,7 @@ @@ -74,6 +74,7 @@
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="Src\AcceptLicensesEventArgs.cs" />
<Compile Include="Src\ClassCodeGenerator.cs" />
<Compile Include="Src\ClassKindUpdater.cs" />
<Compile Include="Src\ConfigSettingsFileSystem.cs" />
<Compile Include="Src\Design\DesignTimeSelectProjectsViewModel.cs" />
<Compile Include="Src\Design\FakePackageOperation.cs" />
@ -152,6 +153,7 @@ @@ -152,6 +153,7 @@
<Compile Include="Src\EnvDTE\vsCMTypeRef.cs" />
<Compile Include="Src\EnvDTE\vsEPReplaceTextOptions.cs" />
<Compile Include="Src\EnvDTE\Window.cs" />
<Compile Include="Src\IClassKindUpdater.cs" />
<Compile Include="Src\IDocumentNamespaceCreator.cs" />
<Compile Include="Src\IProjectBrowserUpdater.cs" />
<Compile Include="Src\IRefactoringDocumentView.cs" />

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

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
// 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 ClassKindUpdater : IClassKindUpdater
{
public ClassKindUpdater(IClass c)
: this(c, new DocumentLoader())
{
}
public ClassKindUpdater(IClass c, IDocumentLoader documentLoader)
{
this.Class = c;
this.DocumentLoader = documentLoader;
}
IClass Class { get; set; }
IDocumentLoader DocumentLoader { get; set; }
IRefactoringDocument Document { get; set; }
public void MakeClassPartial()
{
OpenFileContainingClass();
int offset = GetPartialKeywordInsertOffset();
InsertPartialKeyword(offset);
}
void OpenFileContainingClass()
{
Document = DocumentLoader.LoadRefactoringDocument(Class.CompilationUnit.FileName);
}
int GetPartialKeywordInsertOffset()
{
IRefactoringDocumentLine line = Document.GetLine(Class.Region.BeginLine);
int offset = line.Text.IndexOf(" class", StringComparison.OrdinalIgnoreCase);
if (offset >= 0) {
return offset + line.Offset + 1;
}
throw new ApplicationException("Unable to find 'class' declaration.");
}
void InsertPartialKeyword(int offset)
{
string partialKeyword = GetLanguageSpecificPartialKeyword();
Document.Insert(offset, partialKeyword + " ");
}
string GetLanguageSpecificPartialKeyword()
{
if (Class.ProjectContent.Language == LanguageProperties.VBNet) {
return "Partial";
}
return "partial";
}
}
}

18
src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs

@ -8,8 +8,16 @@ namespace ICSharpCode.PackageManagement.EnvDTE @@ -8,8 +8,16 @@ namespace ICSharpCode.PackageManagement.EnvDTE
{
public class CodeClass2 : CodeClass
{
public CodeClass2(IProjectContent projectContent, IClass c)
IClassKindUpdater classKindUpdater;
public CodeClass2(IProjectContent projectContent, IClass c, IClassKindUpdater classKindUpdater)
: base(projectContent, c)
{
this.classKindUpdater = classKindUpdater;
}
public CodeClass2(IProjectContent projectContent, IClass c)
: this(projectContent, c, new ClassKindUpdater(c))
{
}
@ -34,7 +42,13 @@ namespace ICSharpCode.PackageManagement.EnvDTE @@ -34,7 +42,13 @@ namespace ICSharpCode.PackageManagement.EnvDTE
}
return vsCMClassKind.vsCMClassKindMainClass;
}
set { throw new NotImplementedException(); }
set {
if (value == vsCMClassKind.vsCMClassKindPartialClass) {
classKindUpdater.MakeClassPartial();
} else {
throw new NotImplementedException();
}
}
}
public bool IsAbstract {

12
src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
// 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
{
public interface IClassKindUpdater
{
void MakeClassPartial();
}
}

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

@ -76,6 +76,7 @@ @@ -76,6 +76,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Src\ClassCodeGeneratorTests.cs" />
<Compile Include="Src\ClassKindUpdaterTests.cs" />
<Compile Include="Src\CodeGeneratorTests.cs" />
<Compile Include="Src\EnvDTE\CodeAttribute2Tests.cs" />
<Compile Include="Src\EnvDTE\CodeAttributesTests.cs" />

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

@ -0,0 +1,151 @@ @@ -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 ClassKindUpdaterTests
{
ClassKindUpdater updater;
ClassHelper classHelper;
IRefactoringDocument document;
IDocumentLoader documentLoader;
[SetUp]
public void Init()
{
classHelper = new ClassHelper();
document = MockRepository.GenerateStub<IRefactoringDocument>();
documentLoader = MockRepository.GenerateStub<IDocumentLoader>();
}
void CreatePublicCSharpClass()
{
classHelper.CreatePublicClass("MyClass");
classHelper.ProjectContentHelper.ProjectContentIsForCSharpProject();
}
void CreatePublicVisualBasicClass()
{
classHelper.CreatePublicClass("MyClass");
classHelper.ProjectContentHelper.ProjectContentIsForVisualBasicProject();
}
void SetDocumentFileName(string fileName)
{
documentLoader.Stub(loader => loader.LoadRefactoringDocument(fileName)).Return(document);
}
void CreateClassKindUpdater()
{
updater = new ClassKindUpdater(classHelper.Class, documentLoader);
}
void SetClassFileName(string fileName)
{
classHelper.SetClassFileName(fileName);
SetDocumentFileName(fileName);
}
void SetClassDeclarationLineWithOffset(int line, string text, int offset)
{
classHelper.SetRegionBeginLine(line);
SetDocumentLineText(line, text, offset);
}
void SetClassDeclarationLine(int line, string text)
{
SetClassDeclarationLineWithOffset(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 MakeClassPartial_PublicCSharpClassWithNoOtherModifiers_OpensFileContainingClassInSharpDevelop()
{
CreatePublicCSharpClass();
CreateClassKindUpdater();
string fileName = @"d:\projects\MyProject\MyClass.cs";
SetClassFileName(fileName);
SetClassDeclarationLine(1, "public class MyClass");
updater.MakeClassPartial();
documentLoader.AssertWasCalled(loader => loader.LoadRefactoringDocument(fileName));
}
[Test]
public void MakeClassPartial_PublicCSharpClassWithNoOtherModifiers_AddsPartialKeywordToClassDefinition()
{
CreatePublicCSharpClass();
CreateClassKindUpdater();
SetClassFileName(@"d:\projects\MyProject\MyClass.cs");
SetClassDeclarationLine(1, "public class MyClass");
updater.MakeClassPartial();
document.AssertWasCalled(doc => doc.Insert(7, "partial "));
}
[Test]
public void MakeClassPartial_PublicVisualBasicClassWithNoOtherModifiers_AddsVisualBasicPartialKeywordToClassDefinition()
{
CreatePublicVisualBasicClass();
CreateClassKindUpdater();
SetClassFileName(@"d:\projects\MyProject\MyClass.vb");
SetClassDeclarationLine(1, "Public Class MyClass");
updater.MakeClassPartial();
document.AssertWasCalled(doc => doc.Insert(7, "Partial "));
}
[Test]
public void MakeClassPartial_NoClassKeywordInClassDeclarationLine_ExceptionIsThrown()
{
CreatePublicCSharpClass();
CreateClassKindUpdater();
SetClassFileName(@"d:\projects\MyProject\test.cs");
SetClassDeclarationLine(1, "public test");
Assert.Throws<ApplicationException>(() => updater.MakeClassPartial());
}
[Test]
public void MakeClassPartial_NoClassKeywordButClassNameIncludesClassKeyword_ExceptionIsThrown()
{
CreatePublicCSharpClass();
CreateClassKindUpdater();
SetClassFileName(@"d:\projects\MyProject\MyClass.cs");
SetClassDeclarationLine(1, "public MyClass");
Assert.Throws<ApplicationException>(() => updater.MakeClassPartial());
}
[Test]
public void MakeClassPartial_PublicCSharpClassNotOnFirstLine_AddsPartialKeywordToClassDefinitionAtCorrectOffset()
{
CreatePublicCSharpClass();
CreateClassKindUpdater();
SetClassFileName(@"d:\projects\MyProject\MyClass.cs");
SetClassDeclarationLineWithOffset(1, "public class MyClass", offset: 10);
updater.MakeClassPartial();
document.AssertWasCalled(doc => doc.Insert(17, "partial "));
}
}
}

25
src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.PackageManagement;
using ICSharpCode.PackageManagement.EnvDTE;
using ICSharpCode.SharpDevelop.Dom;
using NUnit.Framework;
@ -16,6 +17,7 @@ namespace PackageManagement.Tests.EnvDTE @@ -16,6 +17,7 @@ namespace PackageManagement.Tests.EnvDTE
{
CodeClass2 codeClass;
ClassHelper helper;
IClassKindUpdater classKindUpdater;
void CreateProjectContent()
{
@ -42,7 +44,8 @@ namespace PackageManagement.Tests.EnvDTE @@ -42,7 +44,8 @@ namespace PackageManagement.Tests.EnvDTE
void CreateClass()
{
codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class);
classKindUpdater = MockRepository.GenerateStub<IClassKindUpdater>();
codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class, classKindUpdater);
}
void AddInterfaceToProjectContent(string fullName)
@ -381,5 +384,25 @@ namespace PackageManagement.Tests.EnvDTE @@ -381,5 +384,25 @@ namespace PackageManagement.Tests.EnvDTE
Assert.IsFalse(generic);
}
[Test]
public void ClassKind_ChangeClassToBePartial_UsesClassKindUpdaterToModifyClass()
{
CreateProjectContent();
CreatePublicClass("MyClass");
codeClass.ClassKind = vsCMClassKind.vsCMClassKindPartialClass;
classKindUpdater.AssertWasCalled(updater => updater.MakeClassPartial());
}
[Test]
public void ClassKind_ChangeClassToBeMainClass_ThrowsNotImplementedException()
{
CreateProjectContent();
CreatePublicClass("MyClass");
Assert.Throws<NotImplementedException>(() => codeClass.ClassKind = vsCMClassKind.vsCMClassKindMainClass);
}
}
}

10
src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs

@ -214,5 +214,15 @@ namespace PackageManagement.Tests.Helpers @@ -214,5 +214,15 @@ namespace PackageManagement.Tests.Helpers
classHelper.CreatePublicClass(name);
return classHelper;
}
public void SetRegionBeginLine(int line)
{
SetRegion(new DomRegion(line, 1));
}
public void SetRegion(DomRegion region)
{
Class.Stub(c => c.Region).Return(region);
}
}
}

Loading…
Cancel
Save