From 8957e14233ef09fe24ed76ca3619e68d3d45e574 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 19 Aug 2012 19:09:35 +0100 Subject: [PATCH 01/53] Create stubs for EnvDTE API used by T4MVC. Minor changes to T4MVC.tt: 1) Change imported assemblies and namespaces to refer to SharpDevelop's implementation of EnvDTE. 2) Change use of parameterised properties to method calls so no VB.NET classes are required. --- .../Project/PackageManagement.csproj | 9 +++++ .../Project/Src/EnvDTE/CodeClass2.cs | 13 ++++++++ .../Project/Src/EnvDTE/CodeFunction.cs | 21 ++++++++++++ .../Project/Src/EnvDTE/CodeFunction2.cs | 22 +++++++++++++ .../Project/Src/EnvDTE/CodeParameter2.cs | 24 ++++++++++++++ .../Project/Src/EnvDTE/CodeType.cs | 5 +++ .../Project/Src/EnvDTE/CodeTypeRef.cs | 4 +++ .../Project/Src/EnvDTE/Constants.cs | 5 +-- .../Project/Src/EnvDTE/Document.cs | 19 +++++++++++ .../Project/Src/EnvDTE/ProjectItem.cs | 13 ++++++-- .../Src/EnvDTE/ProjectItemsInsideProject.cs | 2 +- .../Project/Src/EnvDTE/Projects.cs | 33 ++++++++++++------- .../Project/Src/EnvDTE/Solution.cs | 2 +- .../Project/Src/EnvDTE/Window.cs | 14 ++++++++ .../Project/Src/EnvDTE/vsCMClassKind.cs | 12 +++++++ .../Project/Src/EnvDTE/vsCMFunction.cs | 1 + .../Project/Src/EnvDTE/vsCMOverrideKind.cs | 12 +++++++ .../Project/Src/EnvDTE/vsCMParameterKind.cs | 12 +++++++ .../Project/Src/EnvDTE/vsCMTypeRef.cs | 12 +++++++ .../Project/Src/VisualStudio/SDTE.cs | 14 ++++++++ .../Test/Src/EnvDTE/ProjectItemTests.cs | 4 +-- .../Test/Src/EnvDTE/ProjectItemsTests.cs | 8 ++--- 22 files changed, 237 insertions(+), 24 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index f67b13d684..a8a2cedd71 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -94,10 +94,12 @@ + + @@ -116,6 +118,7 @@ + @@ -132,11 +135,16 @@ + + + + + @@ -450,6 +458,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index b0050fcdcf..e6aebd4c9e 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -22,5 +22,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE IClass baseTypeClass = baseType.GetUnderlyingClass(); return new CodeClass2(projectContent, baseTypeClass); } + + public bool IsGeneric { + get { throw new NotImplementedException(); } + } + + public vsCMClassKind ClassKind { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public bool IsAbstract { + get { throw new NotImplementedException(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index dc90f2ccbf..4673bd2c94 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -58,5 +58,26 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual CodeTypeRef2 Type { get { return new CodeTypeRef2(method.ProjectContent, this, method.ReturnType); } } + + public virtual CodeElements Attributes { + get { throw new NotImplementedException(); } + } + + public virtual bool CanOverride { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public virtual vsCMFunction FunctionKind { + get { throw new NotImplementedException(); } + } + + public virtual bool IsShared { + get { throw new NotImplementedException(); } + } + + public virtual bool MustImplement { + get { throw new NotImplementedException(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs new file mode 100644 index 0000000000..b0a0a20fff --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs @@ -0,0 +1,22 @@ +// 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.EnvDTE +{ + public class CodeFunction2 : CodeFunction + { + public CodeFunction2() + { + } + + public virtual bool IsGeneric { + get { throw new NotImplementedException(); } + } + + public virtual vsCMOverrideKind OverrideKind { + get { throw new NotImplementedException(); } + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs new file mode 100644 index 0000000000..721805894b --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs @@ -0,0 +1,24 @@ +// 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; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class CodeParameter2 : CodeParameter + { + public CodeParameter2(IProjectContent projectContent, IParameter parameter) + : base(projectContent, parameter) + { + } + + public virtual vsCMParameterKind ParameterKind { + get { throw new NotImplementedException(); } + } + + public virtual CodeElements Attributes { + get { throw new NotImplementedException(); } + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs index 71811e8c46..038093e591 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs @@ -77,5 +77,10 @@ namespace ICSharpCode.PackageManagement.EnvDTE return null; } } + + public virtual bool IsDerivedFrom(string fullName) + { + throw new NotImplementedException(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs index 5bfdb6aa17..96adefeb47 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs @@ -44,5 +44,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual CodeType CodeType { get { return new CodeClass2(projectContent, ReturnType.GetUnderlyingClass()); } } + + public virtual vsCMTypeRef TypeKind { + get { throw new NotImplementedException(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs index 1245b8114b..7e7c8164db 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs @@ -7,7 +7,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public static class Constants { - public static readonly string VsProjectItemKindPhysicalFile = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; - public static readonly string VsProjectItemKindPhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsProjectItemKindPhysicalFile = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsProjectItemKindPhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsViewKindCode = "{7651A701-06E5-11D1-8EBD-00A0C90F26EA}"; } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs new file mode 100644 index 0000000000..6784ee97bc --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs @@ -0,0 +1,19 @@ +// 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.EnvDTE +{ + public class Document + { + public Document() + { + } + + public virtual bool Saved { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index 851bf53fb8..ebdaccfff8 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -37,9 +37,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE string GetKindFromFileProjectItemType() { if (IsDirectory) { - return Constants.VsProjectItemKindPhysicalFolder; + return Constants.vsProjectItemKindPhysicalFolder; } - return Constants.VsProjectItemKindPhysicalFile; + return Constants.vsProjectItemKindPhysicalFile; } bool IsDirectory { @@ -164,5 +164,14 @@ namespace ICSharpCode.PackageManagement.EnvDTE { return projectItem.FileName; } + + public Document Document { + get { throw new NotImplementedException(); } + } + + public Window Open(string viewKind) + { + throw new NotImplementedException(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs index 53ef0fa3ff..250fe88a0b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs @@ -128,7 +128,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE { var directoryItem = new FileProjectItem(project.MSBuildProject, ItemType.Folder); directoryItem.Include = directoryName; - return new ProjectItem(project, directoryItem) { Kind = Constants.VsProjectItemKindPhysicalFolder }; + return new ProjectItem(project, directoryItem) { Kind = Constants.vsProjectItemKindPhysicalFolder }; } string GetFirstSubDirectoryName(string include) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs index cd533e8255..822d07b6fa 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs @@ -16,18 +16,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE { this.projectService = projectService; } - - public IEnumerator GetEnumerator() - { - return GetProjectsInSolution().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerable GetProjectsInSolution() + + public IEnumerator GetEnumerator() + { + return GetProjectsInSolution().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerable GetProjectsInSolution() { foreach (SD.MSBuildBasedProject msbuildProject in GetOpenMSBuildProjects()) { yield return new Project(msbuildProject); @@ -38,5 +38,14 @@ namespace ICSharpCode.PackageManagement.EnvDTE { return projectService.GetOpenProjects(); } + + public Project Item(int index) + { + throw new NotImplementedException(); + } + + public virtual int Count { + get { throw new NotImplementedException(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs index 4959e2f86d..97fe25aa69 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE projectService.Save(solution); } - internal bool IsSameSolution(SD.Solution solution) + public ProjectItem FindProjectItem(string fileName) { throw new NotImplementedException(); } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs new file mode 100644 index 0000000000..c73e09bd2d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs @@ -0,0 +1,14 @@ +// 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.EnvDTE +{ + public class Window + { + public Window() + { + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs new file mode 100644 index 0000000000..fc1c5ad1b6 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs @@ -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.EnvDTE +{ + public enum vsCMClassKind + { + vsCMClassKindPartialClass = 4 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs index 56de6e10f4..459a722996 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs @@ -7,6 +7,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMFunction { + vsCMFunctionConstructor = 1, vsCMFunctionFunction = 128 } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs new file mode 100644 index 0000000000..8491407ced --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs @@ -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.EnvDTE +{ + public enum vsCMOverrideKind + { + vsCMOverrideKindOverride = 4 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs new file mode 100644 index 0000000000..6959e8d1d0 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs @@ -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.EnvDTE +{ + public enum vsCMParameterKind + { + vsCMParameterKindOptional = 8 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs new file mode 100644 index 0000000000..3d8dba635d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs @@ -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.EnvDTE +{ + public enum vsCMTypeRef + { + vsCMTypeRefCodeType = 1 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs new file mode 100644 index 0000000000..405c2fa3b7 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs @@ -0,0 +1,14 @@ +// 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 Microsoft.VisualStudio.Shell.Interop +{ + public class SDTE : MarshalByRefObject + { + public SDTE() + { + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index aa2e32456a..6d4f9d9d0f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -106,7 +106,7 @@ namespace PackageManagement.Tests.EnvDTE string kind = directoryItem.Kind; - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, kind); } [Test] @@ -120,7 +120,7 @@ namespace PackageManagement.Tests.EnvDTE string kind = fileItem.Kind; - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFile, kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFile, kind); } [Test] diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs index 5ed756c676..4004d8eaf3 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs @@ -527,7 +527,7 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); } [Test] @@ -592,7 +592,7 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); } [Test] @@ -610,9 +610,9 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); Assert.AreEqual(1, item.ProjectItems.Count); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, childItem.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, childItem.Kind); } [Test] From 8dd6f39aa4f99103c2fe0f77d41ac7171d69dd1a Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 20 Aug 2012 21:11:52 +0100 Subject: [PATCH 02/53] Return SDTE from text template host GetService. T4MVC template requests the SDTE from the text templating host's IServiceProvider implementation and casts it to a DTE. --- .../Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs index 405c2fa3b7..ee1e471937 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs @@ -2,10 +2,11 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using ICSharpCode.PackageManagement.EnvDTE; namespace Microsoft.VisualStudio.Shell.Interop { - public class SDTE : MarshalByRefObject + public class SDTE : DTE { public SDTE() { From d5c579c0ba188181cf8659b1d3dc19e82c2c6f28 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 20 Aug 2012 21:42:31 +0100 Subject: [PATCH 03/53] Implement EnvDTE.Solution.FindProjectItem --- .../Project/Src/EnvDTE/Project.cs | 9 +++ .../Project/Src/EnvDTE/Solution.cs | 9 ++- .../Test/Src/EnvDTE/SolutionTests.cs | 66 +++++++++++++++++++ .../Test/Src/Helpers/SolutionHelper.cs | 25 +++++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index cd45d6a465..f82e536f71 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -280,5 +280,14 @@ namespace ICSharpCode.PackageManagement.EnvDTE { projectService.RemoveProjectItem(MSBuildProject, projectItem.MSBuildProjectItem); } + + internal ProjectItem FindProjectItem(string fileName) + { + SD.FileProjectItem item = MSBuildProject.FindFile(fileName); + if (item != null) { + return new ProjectItem(this, item); + } + return null; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs index 97fe25aa69..1b095a7b34 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using ICSharpCode.SharpDevelop.Project; using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE @@ -46,7 +47,13 @@ namespace ICSharpCode.PackageManagement.EnvDTE public ProjectItem FindProjectItem(string fileName) { - throw new NotImplementedException(); + foreach (Project project in Projects) { + ProjectItem item = project.FindProjectItem(fileName); + if (item != null) { + return item; + } + } + return null; } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs index 5878c1fb16..be2a20d467 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs @@ -38,6 +38,21 @@ namespace PackageManagement.Tests.EnvDTE solutionHelper.AddProjectToSolution(projectName); } + void AddProjectToSolutionWithFileName(string projectName, string fileName) + { + solutionHelper.AddProjectToSolutionWithFileName(projectName, fileName); + } + + void AddFileToFirstProjectInSolution(string fileName) + { + solutionHelper.AddFileToFirstProjectInSolution(fileName); + } + + void AddFileToSecondProjectInSolution(string fileName) + { + solutionHelper.AddFileToSecondProjectInSolution(fileName); + } + [Test] public void IsOpen_NoOpenSolution_ReturnsFalse() { @@ -90,5 +105,56 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("MyProject", project.Name); } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithNoItems_ReturnsNull() + { + CreateSolution(); + AddProjectToSolution("MyProject"); + + ProjectItem item = solution.FindProjectItem(@"c:\projects\MyProject\test.cs"); + + Assert.IsNull(item); + } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithOneItemMatchingFileNamePassedToFindProjectItem_ReturnsProjectItem() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject", @"c:\projects\MyProject\MyProject.csproj"); + AddFileToFirstProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual("test.cs", item.Name); + } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithOneItemMatchingFileNamePassedToFindProjectItem_ProjectItemHasNonNullContainingProject() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject", @"c:\projects\MyProject\MyProject.csproj"); + AddFileToFirstProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual(@"c:\projects\MyProject\MyProject.csproj", item.ContainingProject.FileName); + } + + [Test] + public void FindProjectItem_SolutionHasTwoProjectsWithOneItemMatchingFileNameInSecondProject_ReturnsProjectItem() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject1", @"c:\projects\MyProject1\MyProject.csproj"); + AddProjectToSolutionWithFileName("MyProject2", @"c:\projects\MyProject2\MyProject.csproj"); + AddFileToSecondProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject2\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual("test.cs", item.Name); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs index 90767db0ef..4a0d5fb2f0 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs @@ -49,8 +49,14 @@ namespace PackageManagement.Tests.Helpers } public void AddProjectToSolution(string projectName) + { + AddProjectToSolutionWithFileName(projectName, @"c:\projects\MyProject\MyProject.csproj"); + } + + public void AddProjectToSolutionWithFileName(string projectName, string fileName) { TestableProject project = ProjectHelper.CreateTestProject(projectName); + project.FileName = fileName; FakeProjectService.AddFakeProject(project); } @@ -85,5 +91,24 @@ namespace PackageManagement.Tests.Helpers { Assert.IsNull(FakeProjectService.SavedSolution); } + + public SD.FileProjectItem AddFileToFirstProjectInSolution(string include) + { + TestableProject project = FakeProjectService + .FakeOpenProjects + .Select(p => p as TestableProject) + .First(); + return project.AddFile(include); + } + + public SD.FileProjectItem AddFileToSecondProjectInSolution(string include) + { + TestableProject project = FakeProjectService + .FakeOpenProjects + .Select(p => p as TestableProject) + .Skip(1) + .First(); + return project.AddFile(include); + } } } From 89bce2c9b39e8bf317a487b9403f14bf5428e1ab Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Tue, 21 Aug 2012 07:49:50 +0100 Subject: [PATCH 04/53] Implement EnvDTE.Projects.Item() --- .../Project/Src/EnvDTE/Projects.cs | 8 ++- .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/EnvDTE/ProjectsTests.cs | 52 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs index 822d07b6fa..1eccbd9b4b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE @@ -39,9 +40,14 @@ namespace ICSharpCode.PackageManagement.EnvDTE return projectService.GetOpenProjects(); } + /// + /// Index of 1 returns the first project. + /// public Project Item(int index) { - throw new NotImplementedException(); + return GetProjectsInSolution() + .Skip(index - 1) + .First(); } public virtual int Count { diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index df836b2955..6bf1fe435b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -96,6 +96,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs new file mode 100644 index 0000000000..101bb7a1d2 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs @@ -0,0 +1,52 @@ +// 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.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class ProjectsTests + { + Projects projects; + SolutionHelper solutionHelper; + + void CreateSolutionWithSingleProject(string projectName) + { + solutionHelper = new SolutionHelper(); + solutionHelper.AddProjectToSolution(projectName); + projects = solutionHelper.Solution.Projects; + } + + void CreateSolutionWithTwoProjects(string projectName1, string projectName2) + { + solutionHelper = new SolutionHelper(); + solutionHelper.AddProjectToSolution(projectName1); + solutionHelper.AddProjectToSolution(projectName2); + projects = solutionHelper.Solution.Projects; + } + + [Test] + public void Item_OneProjectAndFirstItemRequested_ReturnsProject() + { + CreateSolutionWithSingleProject("MyProject"); + + Project project = projects.Item(1); + + Assert.AreEqual("MyProject", project.Name); + } + + [Test] + public void Item_TwoProjectsAndSecondItemRequested_ReturnsSecondProject() + { + CreateSolutionWithTwoProjects("MyProject1", "MyProject2"); + + Project project = projects.Item(2); + + Assert.AreEqual("MyProject2", project.Name); + } + } +} From 239d24cf102c4369a7eef3f4804b0ed843971f47 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Tue, 21 Aug 2012 07:55:46 +0100 Subject: [PATCH 05/53] Implement EnvDTE.Projects.Count --- .../Project/Src/EnvDTE/Projects.cs | 4 ++-- .../Test/Src/EnvDTE/ProjectsTests.cs | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs index 1eccbd9b4b..c60763915b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs @@ -50,8 +50,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE .First(); } - public virtual int Count { - get { throw new NotImplementedException(); } + public int Count { + get { return GetProjectsInSolution().Count(); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs index 101bb7a1d2..5a51e64ded 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs @@ -48,5 +48,25 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("MyProject2", project.Name); } + + [Test] + public void Count_OneProject_ReturnsOne() + { + CreateSolutionWithSingleProject("MyProject"); + + int count = projects.Count; + + Assert.AreEqual(1, count); + } + + [Test] + public void Count_TwoProjects_ReturnsTwo() + { + CreateSolutionWithTwoProjects("MyProject1", "MyProject2"); + + int count = projects.Count; + + Assert.AreEqual(2, count); + } } } From 102658b33f3af20312eeb6b1dbb3b37747efd551 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Tue, 21 Aug 2012 20:22:09 +0100 Subject: [PATCH 06/53] Implement EnvDTE.CodeType2.IsAbstract --- .../Project/Src/EnvDTE/CodeClass2.cs | 2 +- .../Test/Src/EnvDTE/CodeClass2Tests.cs | 28 +++++++++++++++++++ .../Test/Src/Helpers/ClassHelper.cs | 5 ++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index e6aebd4c9e..fe9656c8c7 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public bool IsAbstract { - get { throw new NotImplementedException(); } + get { return Class.IsAbstract; } } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index 1f69713ee0..81eb105a3f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -85,6 +85,11 @@ namespace PackageManagement.Tests.EnvDTE helper.AddFieldToClass(fullyQualifiedName); } + void ClassIsAbstract() + { + helper.MakeClassAbstract(); + } + [Test] public void Language_CSharpProject_ReturnsCSharpModelLanguage() { @@ -278,5 +283,28 @@ namespace PackageManagement.Tests.EnvDTE bool contains = properties.Contains(property2); Assert.IsTrue(contains); } + + [Test] + public void IsAbstract_ClassIsAbstract_ReturnsTrue() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsAbstract(); + + bool isAbstract = codeClass.IsAbstract; + + Assert.IsTrue(isAbstract); + } + + [Test] + public void IsAbstract_ClassIsNotAbstract_ReturnsFalse() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + bool isAbstract = codeClass.IsAbstract; + + Assert.IsFalse(isAbstract); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 0db7f57b60..1974caf2ff 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -162,5 +162,10 @@ namespace PackageManagement.Tests.Helpers { ProjectContentHelper.SetProjectForProjectContent(project); } + + public void MakeClassAbstract() + { + Class.Stub(c => c.IsAbstract).Return(true); + } } } From 24955c6960f7bf0ee7a4f3e1cfecab475dd9124a Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Tue, 21 Aug 2012 20:33:45 +0100 Subject: [PATCH 07/53] Implement EnvDTE.CodeClass2.ClassKind getter. --- .../Project/Src/EnvDTE/CodeClass2.cs | 7 ++++- .../Project/Src/EnvDTE/vsCMClassKind.cs | 1 + .../Test/Src/EnvDTE/CodeClass2Tests.cs | 28 +++++++++++++++++++ .../Test/Src/Helpers/ClassHelper.cs | 5 ++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index fe9656c8c7..3b8f72a3be 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -28,7 +28,12 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public vsCMClassKind ClassKind { - get { throw new NotImplementedException(); } + get { + if (Class.IsPartial) { + return vsCMClassKind.vsCMClassKindPartialClass; + } + return vsCMClassKind.vsCMClassKindMainClass; + } set { throw new NotImplementedException(); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs index fc1c5ad1b6..05c70f5c68 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs @@ -7,6 +7,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMClassKind { + vsCMClassKindMainClass = 1, vsCMClassKindPartialClass = 4 } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index 81eb105a3f..f27089e129 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -90,6 +90,11 @@ namespace PackageManagement.Tests.EnvDTE helper.MakeClassAbstract(); } + void ClassIsPartial() + { + helper.MakeClassPartial(); + } + [Test] public void Language_CSharpProject_ReturnsCSharpModelLanguage() { @@ -306,5 +311,28 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsFalse(isAbstract); } + + [Test] + public void ClassKind_ClassIsPartial_ReturnsPartialClassKind() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsPartial(); + + vsCMClassKind kind = codeClass.ClassKind; + + Assert.AreEqual(vsCMClassKind.vsCMClassKindPartialClass, kind); + } + + [Test] + public void ClassKind_ClassIsNotPartial_ReturnsMainClassKind() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + vsCMClassKind kind = codeClass.ClassKind; + + Assert.AreEqual(vsCMClassKind.vsCMClassKindMainClass, kind); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 1974caf2ff..f79cbd8e5b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -167,5 +167,10 @@ namespace PackageManagement.Tests.Helpers { Class.Stub(c => c.IsAbstract).Return(true); } + + public void MakeClassPartial() + { + Class.Stub(c => c.IsPartial).Return(true); + } } } From f81c495eac0b32213550ae5770fed4fd7052a7d7 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 22 Aug 2012 21:30:07 +0100 Subject: [PATCH 08/53] Add classes to EnvDTE.FileCodeModel2.CodeElements --- .../Project/PackageManagement.csproj | 2 + .../Project/Src/EnvDTE/CodeNamespace.cs | 2 +- .../Src/EnvDTE/FileCodeModelCodeElements.cs | 33 ++++++++ .../Src/EnvDTE/FileCodeModelCodeNamespace.cs | 38 +++++++++ .../FileCodeModelCodeNamespaceMembers.cs | 21 +++++ .../Test/Src/EnvDTE/FileCodeModel2Tests.cs | 81 ++++++++++++++++++- .../Test/Src/Helpers/ClassHelper.cs | 8 ++ .../Src/Helpers/CodeElementsExtensions.cs | 5 ++ .../Test/Src/Helpers/CompilationUnitHelper.cs | 2 + .../Test/Src/Helpers/UsingScopeHelper.cs | 5 ++ 10 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index a8a2cedd71..2e5b3dc0bc 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -122,6 +122,8 @@ + + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs index 9c93be2971..a5b323dff9 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE get { return namespaceName.LastPart; } } - public CodeElements Members { + public virtual CodeElements Members { get { return new CodeElementsInNamespace(projectContent, namespaceName); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs index 2ee8af40d5..39bb3f4636 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -11,6 +12,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE public class FileCodeModelCodeElements : CodeElementsList { ICompilationUnit compilationUnit; + List fileCodeModelNamespaces = new List(); public FileCodeModelCodeElements(ICompilationUnit compilationUnit) { @@ -23,6 +25,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE foreach (IUsing namespaceUsing in GetNamespaceImports()) { AddNamespaceImport(namespaceUsing); } + AddClasses(); } IList GetNamespaceImports() @@ -36,5 +39,35 @@ namespace ICSharpCode.PackageManagement.EnvDTE { AddCodeElement(new CodeImport(import)); } + + void AddClasses() + { + foreach (IClass c in compilationUnit.Classes) { + FileCodeModelCodeNamespace codeNamespace = GetOrCreateFileCodeModelNamespace(c); + codeNamespace.AddClass(compilationUnit.ProjectContent, c); + } + } + + FileCodeModelCodeNamespace GetOrCreateFileCodeModelNamespace(IClass c) + { + var codeNamespace = FindFileCodeModelNamespace(c); + if (codeNamespace != null) { + return codeNamespace; + } + return CreateFileCodeModelNamespace(c); + } + + FileCodeModelCodeNamespace FindFileCodeModelNamespace(IClass c) + { + return fileCodeModelNamespaces.FirstOrDefault(ns => ns.FullName == c.Namespace); + } + + FileCodeModelCodeNamespace CreateFileCodeModelNamespace(IClass c) + { + var codeNamespace = new FileCodeModelCodeNamespace(compilationUnit.ProjectContent, c.Namespace); + AddCodeElement(codeNamespace); + fileCodeModelNamespaces.Add(codeNamespace); + return codeNamespace; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs new file mode 100644 index 0000000000..12fb129859 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs @@ -0,0 +1,38 @@ +// 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; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + /// + /// File code model namespaces take the full name of the namespace that a class + /// is inside. So for the FileCodeModelNamespace class the CodeNamespace.Name + /// would be ICSharpCode.PackageManagement.EnvDTE. + /// This differs from the CodeModel CodeNamespace which breaks up the namespaces into + /// parts. + /// + public class FileCodeModelCodeNamespace : CodeNamespace + { + FileCodeModelCodeNamespaceMembers members = new FileCodeModelCodeNamespaceMembers(); + + public FileCodeModelCodeNamespace(IProjectContent projectContent, string namespaceName) + : base(projectContent, namespaceName) + { + } + + public override string Name { + get { return base.FullName; } + } + + public override CodeElements Members { + get { return members; } + } + + public void AddClass(IProjectContent projectContent, IClass c) + { + members.AddClass(projectContent, c); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs new file mode 100644 index 0000000000..99e00c8c58 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs @@ -0,0 +1,21 @@ +// 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; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class FileCodeModelCodeNamespaceMembers : CodeElementsList + { + public FileCodeModelCodeNamespaceMembers() + { + } + + public void AddClass(IProjectContent projectContent, IClass c) + { + var codeClass = new CodeClass2(projectContent, c); + AddCodeElement(codeClass); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs index ec7dcb8d5a..8f78b1b84e 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs @@ -56,6 +56,11 @@ namespace PackageManagement.Tests.EnvDTE return fileCodeModel.CodeElements.FirstCodeImportOrDefault(); } + CodeNamespace GetFirstCodeNamespaceFromCodeElements() + { + return fileCodeModel.CodeElements.FirstCodeNamespaceOrDefault(); + } + void AddNamespaceToCompilationUnit(string namespaceName) { compilationUnitHelper.AddNamespace(namespaceName); @@ -65,7 +70,21 @@ namespace PackageManagement.Tests.EnvDTE { compilationUnitHelper.AddNamespaceAlias(alias, namespaceName); } - + + void AddClassToCompilationUnit(string namespaceName, string className) + { + var classHelper = new ClassHelper(); + classHelper.CreatePublicClass(className); + classHelper.AddNamespaceUsingScopeToClass(namespaceName); + classHelper.AddClassNamespace(namespaceName); + compilationUnitHelper.AddClass(classHelper.Class); + } + + CodeNamespace GetLastCodeNamespaceFromCodeElements() + { + return fileCodeModel.CodeElements.LastCodeNamespaceOrDefault(); + } + [Test] public void CodeElements_OneNamespaceInFile_FileNameUsedToGetCompilationUnit() { @@ -116,5 +135,65 @@ namespace PackageManagement.Tests.EnvDTE namespaceCreator.AssertWasCalled(creator => creator.AddNamespace(compilationUnitHelper.CompilationUnit, "System.Xml")); } + + [Test] + public void CodeElements_OneClassInFileWithNamespace_ReturnsOneCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + + Assert.AreEqual("Test.CodeModel", ns.Name); + } + + [Test] + public void CodeElements_OneClassInFileWithNamespace_ReturnsOneClassInsideCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + CodeClass2 codeClass = ns.Members.FirstCodeClass2OrDefault(); + + Assert.AreEqual("Test.CodeModel.Class1", codeClass.FullName); + } + + [Test] + public void CodeElements_TwoClassesInFileWithNamespace_ReturnsTwoClassesInsideCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class2"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + CodeClass2 codeClass1 = ns.Members.FirstCodeClass2OrDefault(); + CodeClass2 codeClass2 = ns.Members.LastCodeClass2OrDefault(); + + Assert.AreEqual("Test.CodeModel.Class1", codeClass1.FullName); + Assert.AreEqual("Test.CodeModel.Class2", codeClass2.FullName); + } + + [Test] + public void CodeElements_TwoClassesInFileEachWithDifferentNamespace_ReturnsTwoCodeNamespaces() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel1", "Test.CodeModel.Class1"); + AddClassToCompilationUnit("Test.CodeModel2", "Test.CodeModel.Class2"); + CreateFileCodeModel(); + + CodeNamespace ns1 = GetFirstCodeNamespaceFromCodeElements(); + CodeNamespace ns2 = GetLastCodeNamespaceFromCodeElements(); + + Assert.AreEqual("Test.CodeModel1", ns1.Name); + Assert.AreEqual("Test.CodeModel2", ns2.Name); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index f79cbd8e5b..0d32a8e6b8 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -172,5 +172,13 @@ namespace PackageManagement.Tests.Helpers { Class.Stub(c => c.IsPartial).Return(true); } + + public void AddNamespaceUsingScopeToClass(string namespaceName) + { + var usingScopeHelper = new UsingScopeHelper(); + usingScopeHelper.SetNamespaceName(namespaceName); + + Class.Stub(c => c.UsingScope).Return(usingScopeHelper.UsingScope); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs index e55fa0c2d9..87e6749f84 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs @@ -83,5 +83,10 @@ namespace PackageManagement.Tests.Helpers { return codeElements.FirstOrDefault() as CodeImport; } + + public static CodeClass2 LastCodeClass2OrDefault(this CodeElements codeElements) + { + return codeElements.LastOrDefault() as CodeClass2; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs index 3ff65181f7..73c4284b78 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs @@ -14,6 +14,7 @@ namespace PackageManagement.Tests.Helpers public FakeCodeGenerator FakeCodeGenerator = new FakeCodeGenerator(); public List Classes = new List(); public UsingScopeHelper UsingScopeHelper = new UsingScopeHelper(); + public ProjectContentHelper ProjectContentHelper = new ProjectContentHelper(); public CompilationUnitHelper() { @@ -23,6 +24,7 @@ namespace PackageManagement.Tests.Helpers CompilationUnit.Stub(unit => unit.Language).Return(language); CompilationUnit.Stub(unit => unit.Classes).Return(Classes); CompilationUnit.Stub(unit => unit.UsingScope).Return(UsingScopeHelper.UsingScope); + CompilationUnit.Stub(unit => unit.ProjectContent).Return(ProjectContentHelper.ProjectContent); } public void SetFileName(string fileName) diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs index b6674a563d..be4cf51948 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs @@ -37,5 +37,10 @@ namespace PackageManagement.Tests.Helpers usingHelper.AddNamespaceAlias(alias, namespaceName); Usings.Add(usingHelper.Using); } + + public void SetNamespaceName(string namespaceName) + { + UsingScope.Stub(u => u.NamespaceName).Return(namespaceName); + } } } From b6aa67a6e2c708ac19dc12c898fc1cb9a6701acd Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 25 Aug 2012 14:54:01 +0100 Subject: [PATCH 09/53] Fix EnvDTE.ProjectItems.Item not returning correct items for child directories. --- .../Project/Src/EnvDTE/ChildProjectItems.cs | 6 ++++++ .../Project/Src/EnvDTE/DirectoryProjectItems.cs | 6 ++++++ .../Test/Src/EnvDTE/ProjectItemsTests.cs | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs index f04a8e55b1..1253837d5f 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs @@ -68,5 +68,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE ProjectItems.Add(childProjectItem); return false; } + + public ProjectItem GetItem(int index) + { + List projectItems = GetProjectItems().ToList(); + return projectItems[index]; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs index 0d76dce23e..ca18a74084 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs @@ -21,5 +21,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE var items = new ChildProjectItems(projectItem); return items.GetEnumerator(); } + + internal override ProjectItem Item(int index) + { + var items = new ChildProjectItems(projectItem); + return items.GetItem(index - 1); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs index 4004d8eaf3..9fec6053a6 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs @@ -815,5 +815,21 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsTrue(fileItem.IsLink); Assert.AreEqual("test.cs", linkName); } + + [Test] + public void Item_GetItemFromControllersFolderProjectItemsWhenProjectHasTwoFilesOneInRootAndOneInControllersFolder_ReturnsFileFromControllersFolder() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"AccountController.generated.cs"); + msbuildProject.AddFile(@"Controllers\AccountController.cs"); + + DTE.ProjectItem projectItem = projectItems + .Item("Controllers") + .ProjectItems + .Item(1); + + Assert.AreEqual("AccountController.cs", projectItem.Name); + } } } From 8dab965c7df00d0bd7b5286292361aea5c3171aa Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 25 Aug 2012 15:09:31 +0100 Subject: [PATCH 10/53] Refactor EnvDTE.ProjectItems. Remove code duplication in ProjectItems classes. --- .../Project/PackageManagement.csproj | 1 + .../Project/Src/EnvDTE/ChildProjectItems.cs | 22 ++----------- .../Src/EnvDTE/DirectoryProjectItems.cs | 12 ++----- .../Src/EnvDTE/EnumerableProjectItems.cs | 33 +++++++++++++++++++ .../Project/Src/EnvDTE/ProjectItems.cs | 15 ++++++--- .../Src/EnvDTE/ProjectItemsInsideProject.cs | 26 ++------------- 6 files changed, 51 insertions(+), 58 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index 2e5b3dc0bc..d26639408e 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -120,6 +120,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs index 1253837d5f..d1548b0569 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs @@ -2,7 +2,6 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,7 +11,7 @@ using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class ChildProjectItems : IEnumerable + public class ChildProjectItems : EnumerableProjectItems { public ChildProjectItems(ProjectItem projectItem) { @@ -25,18 +24,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE Project Project { get; set; } List ProjectItems { get; set; } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - List projectItems = GetProjectItems().ToList(); - return projectItems.GetEnumerator(); - } - - IEnumerable GetProjectItems() + protected override IEnumerable GetProjectItems() { foreach (SD.ProjectItem msbuildProjectItem in Project.MSBuildProject.Items) { ProjectItem item = GetChildProjectItem(msbuildProjectItem); @@ -68,11 +56,5 @@ namespace ICSharpCode.PackageManagement.EnvDTE ProjectItems.Add(childProjectItem); return false; } - - public ProjectItem GetItem(int index) - { - List projectItems = GetProjectItems().ToList(); - return projectItems[index]; - } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs index ca18a74084..1569024717 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs @@ -3,6 +3,7 @@ using System; using System.Collections; +using System.Collections.Generic; namespace ICSharpCode.PackageManagement.EnvDTE { @@ -16,16 +17,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE this.projectItem = projectItem; } - public override IEnumerator GetEnumerator() + protected override IEnumerable GetProjectItems() { - var items = new ChildProjectItems(projectItem); - return items.GetEnumerator(); - } - - internal override ProjectItem Item(int index) - { - var items = new ChildProjectItems(projectItem); - return items.GetItem(index - 1); + return new ChildProjectItems(projectItem); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs new file mode 100644 index 0000000000..62e554ea5a --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs @@ -0,0 +1,33 @@ +// 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 System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public abstract class EnumerableProjectItems : IEnumerable + { + public EnumerableProjectItems() + { + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return GetProjectItems().GetEnumerator(); + } + + protected abstract IEnumerable GetProjectItems(); + + internal virtual int Count { + get { return GetProjectItems().Count(); } + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs index 37ce66d606..e1b4d3cf1e 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs @@ -73,8 +73,12 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual IEnumerator GetEnumerator() { - var items = new ProjectItemsInsideProject(project); - return items.GetEnumerator(); + return GetProjectItems().GetEnumerator(); + } + + protected virtual IEnumerable GetProjectItems() + { + return new ProjectItemsInsideProject(project); } internal virtual ProjectItem Item(string name) @@ -89,8 +93,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE internal virtual ProjectItem Item(int index) { - var items = new ProjectItemsInsideProject(project); - return items.GetItem(index - 1); + return GetProjectItems() + .Skip(index - 1) + .First(); } public virtual ProjectItem Item(object index) @@ -121,7 +126,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual int Count { - get { return new ProjectItemsInsideProject(project).Count; } + get { return GetProjectItems().Count(); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs index 250fe88a0b..456aea1a08 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs @@ -2,7 +2,6 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,7 +11,7 @@ using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class ProjectItemsInsideProject : IEnumerable + public class ProjectItemsInsideProject : EnumerableProjectItems { Project project; Dictionary directoriesIncluded = new Dictionary(); @@ -22,17 +21,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE this.project = project; } - public IEnumerator GetEnumerator() - { - List projectItems = GetProjectItems().ToList(); - return projectItems.GetEnumerator(); - } - - internal virtual int Count { - get { return GetProjectItems().Count(); } - } - - IEnumerable GetProjectItems() + protected override IEnumerable GetProjectItems() { foreach (SD.ProjectItem item in project.MSBuildProject.Items) { ProjectItem projectItem = ConvertToProjectItem(item); @@ -136,16 +125,5 @@ namespace ICSharpCode.PackageManagement.EnvDTE string[] directoryNames = include.Split('\\'); return directoryNames[0]; } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - internal ProjectItem GetItem(int index) - { - List projectItems = GetProjectItems().ToList(); - return projectItems[index]; - } } } From 9963d624682d22137c628835cc168698c23cf73f Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 25 Aug 2012 16:46:45 +0100 Subject: [PATCH 11/53] Implement EnvDTE.CodeClass2.IsGeneric The T4MVC template checks for generic controller classes and does not process them. --- .../Project/Src/EnvDTE/CodeClass2.cs | 2 +- .../Test/Src/EnvDTE/CodeClass2Tests.cs | 34 +++++++++++++++++++ .../Test/Src/Helpers/ClassHelper.cs | 5 +++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index 3b8f72a3be..dbca938a8f 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public bool IsGeneric { - get { throw new NotImplementedException(); } + get { return Class.DotNetName.Contains("`"); } } public vsCMClassKind ClassKind { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index f27089e129..fc0f0794f8 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -95,6 +95,16 @@ namespace PackageManagement.Tests.EnvDTE helper.MakeClassPartial(); } + void ClassIsGeneric() + { + helper.SetDotNetName("MyClass`1"); + } + + void ClassIsNotGeneric() + { + helper.SetDotNetName("MyClass"); + } + [Test] public void Language_CSharpProject_ReturnsCSharpModelLanguage() { @@ -334,5 +344,29 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(vsCMClassKind.vsCMClassKindMainClass, kind); } + + [Test] + public void IsGeneric_ClassIsGeneric_ReturnsTrue() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsGeneric(); + + bool generic = codeClass.IsGeneric; + + Assert.IsTrue(generic); + } + + [Test] + public void IsGeneric_ClassIsNotGeneric_ReturnsFalse() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsNotGeneric(); + + bool generic = codeClass.IsGeneric; + + Assert.IsFalse(generic); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 0d32a8e6b8..55353ee3c7 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -180,5 +180,10 @@ namespace PackageManagement.Tests.Helpers Class.Stub(c => c.UsingScope).Return(usingScopeHelper.UsingScope); } + + public void SetDotNetName(string className) + { + Class.Stub(c => c.DotNetName).Return(className); + } } } From 085dd5f0f52f4abc5dfd170134f0c2ab4799c482 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 25 Aug 2012 18:15:45 +0100 Subject: [PATCH 12/53] Implement EnvDTE.CodeTypeRef.TypeKind. The T4MVC template ignores methods that return something other than a reference type. --- .../Project/Src/EnvDTE/CodeTypeRef.cs | 2 +- .../Src/EnvDTE/IReturnTypeExtensions.cs | 47 +++++ .../Project/Src/EnvDTE/vsCMTypeRef.cs | 18 +- .../Test/Src/EnvDTE/CodeTypeRef2Tests.cs | 190 ++++++++++++++++++ .../Test/Src/Helpers/ReturnTypeHelper.cs | 5 + 5 files changed, 260 insertions(+), 2 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs index 96adefeb47..6c1aa2b600 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs @@ -46,7 +46,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual vsCMTypeRef TypeKind { - get { throw new NotImplementedException(); } + get { return ReturnType.GetTypeKind(); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs index 492b1f7e38..ca3b769d7c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs @@ -35,5 +35,52 @@ namespace ICSharpCode.PackageManagement.EnvDTE } return returnType.GetFullName(); } + + public static vsCMTypeRef GetTypeKind(this IReturnType returnType) + { + vsCMTypeRef typeRef = GetSystemTypeKind(returnType.FullyQualifiedName); + if (typeRef != vsCMTypeRef.vsCMTypeRefOther) { + return typeRef; + } + + if (returnType.IsReferenceType.GetValueOrDefault()) { + return vsCMTypeRef.vsCMTypeRefCodeType; + } + return vsCMTypeRef.vsCMTypeRefOther; + } + + static vsCMTypeRef GetSystemTypeKind(string fullyQualifiedTypeName) + { + switch (fullyQualifiedTypeName) { + case "System.String": + return vsCMTypeRef.vsCMTypeRefString; + case "System.Void": + return vsCMTypeRef.vsCMTypeRefVoid; + case "System.Boolean": + return vsCMTypeRef.vsCMTypeRefBool; + case "System.Int16": + case "System.UInt16": + return vsCMTypeRef.vsCMTypeRefShort; + case "System.Int32": + case "System.UInt32": + return vsCMTypeRef.vsCMTypeRefInt; + case "System.Int64": + case "System.UInt64": + return vsCMTypeRef.vsCMTypeRefLong; + case "System.Decimal": + return vsCMTypeRef.vsCMTypeRefDecimal; + case "System.Char": + return vsCMTypeRef.vsCMTypeRefChar; + case "System.Byte": + return vsCMTypeRef.vsCMTypeRefByte; + case "System.Object": + return vsCMTypeRef.vsCMTypeRefObject; + case "System.Double": + return vsCMTypeRef.vsCMTypeRefDouble; + case "System.Single": + return vsCMTypeRef.vsCMTypeRefFloat; + } + return vsCMTypeRef.vsCMTypeRefOther; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs index 3d8dba635d..670eb8549d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs @@ -7,6 +7,22 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMTypeRef { - vsCMTypeRefCodeType = 1 + vsCMTypeRefOther = 0, + vsCMTypeRefCodeType = 1, + vsCMTypeRefArray = 2, + vsCMTypeRefVoid = 3, + vsCMTypeRefPointer = 4, + vsCMTypeRefString = 5, + vsCMTypeRefObject = 6, + vsCMTypeRefByte = 7, + vsCMTypeRefChar = 8, + vsCMTypeRefShort = 9, + vsCMTypeRefInt = 10, + vsCMTypeRefLong = 11, + vsCMTypeRefFloat = 12, + vsCMTypeRefDouble = 13, + vsCMTypeRefDecimal = 14, + vsCMTypeRefBool = 15, + vsCMTypeRefVariant = 16 } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs index 9855719155..68a2acad41 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs @@ -187,5 +187,195 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("Test.MyClass", name); } + + [Test] + public void TypeKind_ReturnTypeIsReferenceType_ReturnsClassType() + { + helper.CreateReturnType("Test.MyClass"); + AddUnderlyingClassToReturnType("Test.MyClass"); + helper.MakeReferenceType(); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefCodeType, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsNotReferenceType_ReturnsNonClassType() + { + helper.CreateReturnType("Test.MyClass"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefOther, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemVoid_ReturnsVoidType() + { + helper.CreateReturnType("System.Void"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefVoid, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemString_ReturnsStringType() + { + helper.CreateReturnType("System.String"); + helper.MakeReferenceType(); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefString, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemBoolean_ReturnsBooleanType() + { + helper.CreateReturnType("System.Boolean"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefBool, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemByte_ReturnsByteType() + { + helper.CreateReturnType("System.Byte"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefByte, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemChar_ReturnsCharType() + { + helper.CreateReturnType("System.Char"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefChar, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemDecimal_ReturnsDecimalType() + { + helper.CreateReturnType("System.Decimal"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefDecimal, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemDouble_ReturnsDoubleType() + { + helper.CreateReturnType("System.Double"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefDouble, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemSingle_ReturnsFloatType() + { + helper.CreateReturnType("System.Single"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefFloat, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt32_ReturnsIntType() + { + helper.CreateReturnType("System.Int32"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefInt, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt16_ReturnsShortType() + { + helper.CreateReturnType("System.Int16"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefShort, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt64_ReturnsLongType() + { + helper.CreateReturnType("System.Int64"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefLong, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt32_ReturnsIntType() + { + helper.CreateReturnType("System.UInt32"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefInt, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt16_ReturnsShortType() + { + helper.CreateReturnType("System.UInt16"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefShort, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt64_ReturnsLongType() + { + helper.CreateReturnType("System.UInt64"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefLong, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemObject_ReturnsObjectType() + { + helper.CreateReturnType("System.Object"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefObject, kind); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs index cc2e60c826..8999819495 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs @@ -32,5 +32,10 @@ namespace PackageManagement.Tests.Helpers { ReturnType.Stub(t => t.GetUnderlyingClass()).Return(c); } + + public void MakeReferenceType() + { + ReturnType.Stub(t => t.IsReferenceType).Return(true); + } } } From f8a9a0cff6ac7e629e251d159ed52890d17f110c Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 11:53:19 +0100 Subject: [PATCH 13/53] Implement EnvDTE.CodeType.IsDerivedFrom() The T4MVC template checks that controller action methods return a class derived from System.Web.Mvc.ActionResult. --- .../Project/PackageManagement.csproj | 1 + .../Project/Src/EnvDTE/CodeType.cs | 9 ++- .../Project/Src/EnvDTE/IClassExtensions.cs | 43 +++++++++++ .../Project/Src/EnvDTE/ProjectItem.cs | 5 ++ .../Test/Src/EnvDTE/CodeTypeTests.cs | 75 ++++++++++++++++++- .../Test/Src/Helpers/ClassHelper.cs | 33 +++++++- 6 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index d26639408e..61e8ad740e 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -125,6 +125,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs index 038093e591..eb7838dfc5 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -72,15 +73,19 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual ProjectItem ProjectItem { get { if (ProjectContent.Project != null) { - return new ProjectItem((MSBuildBasedProject)ProjectContent.Project, Class); + return new ProjectItem(ProjectContent, Class); } return null; } } + /// + /// Returns true if the current type matches the fully qualified name or any of its + /// base types are a match. + /// public virtual bool IsDerivedFrom(string fullName) { - throw new NotImplementedException(); + return Class.IsDerivedFrom(fullName); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs new file mode 100644 index 0000000000..68d38b9081 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs @@ -0,0 +1,43 @@ +// 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 System.Linq; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class IClassExtensions + { + /// + /// Returns true if the class fully qualified name matches the name or + /// any class in the inheritance tree matches the name. + /// + public static bool IsDerivedFrom(this IClass c, string typeName) + { + if (c.FullyQualifiedName == typeName) { + return true; + } + + if (TypeNameMatchesBaseType(c.BaseType, typeName)) { + return true; + } + + return IsTypeInClassInheritanceTree(c, typeName); + } + + static bool TypeNameMatchesBaseType(IReturnType baseType, string typeName) + { + return + (baseType != null) && + (baseType.FullyQualifiedName == typeName); + } + + static bool IsTypeInClassInheritanceTree(IClass c, string typeName) + { + return c + .ClassInheritanceTreeClassesOnly + .Any(inheritedClass => inheritedClass.FullyQualifiedName == typeName); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index ebdaccfff8..747dee441b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -34,6 +34,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE { } + internal ProjectItem(IProjectContent projectContent, IClass c) + : this((MSBuildBasedProject)projectContent.Project, c) + { + } + string GetKindFromFileProjectItemType() { if (IsDirectory) { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs index 0615a38957..4935c36043 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs @@ -46,7 +46,15 @@ namespace PackageManagement.Tests.EnvDTE SDProject.FileProjectItem AddFileToProjectAndProjectContent(TestableProject project, string fileName) { helper.CompilationUnitHelper.SetFileName(fileName); - return project.AddFile(fileName); + return project.AddFile(fileName); + } + + /// + /// Classes at the end of the array are at the top of the inheritance tree. + /// + void AddClassInheritanceTree(params string[] classNames) + { + helper.AddClassInheritanceTreeClassesOnly(classNames); } [Test] @@ -121,5 +129,70 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("test.cs", item.Name); } + + [Test] + public void IsDerivedFrom_ClassFullyQualifiedNameMatchesTypeNameBeingChecked_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassFullyQualifiedNameDoesNotMatcheTypeNameBeingChecked_ReturnsFalse() + { + CreateProjectContent(); + CreateClass("TestClass"); + AddClassInheritanceTree("System.Object"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsFalse(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassBaseTypeFullyQualifiedNameMatchesTypeName_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + helper.AddBaseTypeToClass("System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassHasTypeInClassInheritanceTreeButNotImmediateBaseType_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + AddClassInheritanceTree("CustomActionResultBase", "System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassHasClassInInheritanceTreeButNotImmediateParentAndClassBaseTypePropertyIsNotNull_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + helper.AddBaseTypeToClass("CustomActionResultBase"); + AddClassInheritanceTree("CustomActionResultBase", "System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 55353ee3c7..124e4853a2 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using Rhino.Mocks; @@ -66,13 +67,18 @@ namespace PackageManagement.Tests.Helpers Class.Stub(c => c.BaseTypes).Return(baseTypes); } - IReturnType CreateBaseType(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) + ReturnTypeHelper CreateBaseTypeHelper(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) { var returnTypeHelper = new ReturnTypeHelper(); returnTypeHelper.CreateReturnType(baseTypeFullName); returnTypeHelper.AddUnderlyingClass(baseTypeClass); returnTypeHelper.AddDotNetName(baseTypeDotNetName); - return returnTypeHelper.ReturnType; + return returnTypeHelper; + } + + IReturnType CreateBaseType(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) + { + return CreateBaseTypeHelper(baseTypeClass, baseTypeFullName, baseTypeDotNetName).ReturnType; } public void AddClassToClassBaseTypes(string fullName) @@ -185,5 +191,28 @@ namespace PackageManagement.Tests.Helpers { Class.Stub(c => c.DotNetName).Return(className); } + + /// + /// Classes at the end of the array are at the top of the inheritance tree. + /// + public void AddClassInheritanceTreeClassesOnly(params string[] classNames) + { + List classes = CreateClassInheritanceTree(classNames); + Class.Stub(c => c.ClassInheritanceTreeClassesOnly).Return(classes); + } + + List CreateClassInheritanceTree(string[] classNames) + { + return classNames + .Select(name => CreateClassHelperWithPublicClass(name).Class) + .ToList(); + } + + ClassHelper CreateClassHelperWithPublicClass(string name) + { + var classHelper = new ClassHelper(); + classHelper.CreatePublicClass(name); + return classHelper; + } } } From 5e0d6c3475870f2a262e6cd00b198c2f1794b265 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 12:15:55 +0100 Subject: [PATCH 14/53] Implement EnvDTE.CodeFunction.FunctionKind CodeFunction.FunctionKind currently only detects if the method is a constructor or a normal method. --- .../Project/Src/EnvDTE/CodeFunction.cs | 10 ++++++- .../Project/Src/EnvDTE/vsCMFunction.cs | 3 ++- .../Src/IMethodOrPropertyExtensions.cs | 9 +++++++ .../Test/Src/EnvDTE/CodeFunctionTests.cs | 26 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 6 +++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index 4673bd2c94..ed8ca04743 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -69,7 +69,15 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual vsCMFunction FunctionKind { - get { throw new NotImplementedException(); } + get { return GetFunctionKind(); } + } + + vsCMFunction GetFunctionKind() + { + if (method.IsConstructor()) { + return vsCMFunction.vsCMFunctionConstructor; + } + return vsCMFunction.vsCMFunctionFunction; } public virtual bool IsShared { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs index 459a722996..f74bc36afe 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs @@ -7,7 +7,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMFunction { + vsCMFunctionOther = 0, vsCMFunctionConstructor = 1, - vsCMFunctionFunction = 128 + vsCMFunctionFunction = 128 } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs index aea93f505e..e81b599bd0 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs @@ -25,5 +25,14 @@ namespace ICSharpCode.PackageManagement { return method.DeclaringType.ClassType == ClassType.Interface; } + + public static bool IsConstructor(this IMethodOrProperty methodOrProperty) + { + var method = methodOrProperty as IMethod; + if (method != null) { + return method.IsConstructor; + } + return false; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index 9fd2169bf4..dc7ef7ec34 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -39,6 +39,12 @@ namespace PackageManagement.Tests.EnvDTE codeFunction = new CodeFunction(helper.Method); } + void CreatePublicConstructor(string name) + { + helper.CreatePublicConstructor(name); + CreateFunction(); + } + void SetDeclaringTypeAsInterface(string name) { helper.AddDeclaringTypeAsInterface(name); @@ -246,5 +252,25 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(codeFunction, typeRef.Parent); } + + [Test] + public void FunctionKind_ClassMethod_ReturnsFunctionKind() + { + CreatePublicFunction("MyClass.MyFunction"); + + vsCMFunction kind = codeFunction.FunctionKind; + + Assert.AreEqual(vsCMFunction.vsCMFunctionFunction, kind); + } + + [Test] + public void FunctionKind_ClassConstructor_ReturnsConstructorKind() + { + CreatePublicConstructor("MyClass.MyClass"); + + vsCMFunction kind = codeFunction.FunctionKind; + + Assert.AreEqual(vsCMFunction.vsCMFunctionConstructor, kind); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index f5960c5a66..946e6e8400 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -29,6 +29,12 @@ namespace PackageManagement.Tests.Helpers Method.Stub(m => m.IsPublic).Return(true); } + public void CreatePublicConstructor(string name) + { + CreatePublicMethod(name); + Method.Stub(m => m.IsConstructor).Return(true); + } + public void CreatePrivateMethod(string name) { CreateMethod(name); From 81671a907d8b711a3a405e4b81b394cdd42399e8 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 12:26:56 +0100 Subject: [PATCH 15/53] Implement EnvDTE.CodeFunction.IsShared Returns true if the method is static. --- .../Project/Src/EnvDTE/CodeFunction.cs | 2 +- .../Test/Src/EnvDTE/CodeFunctionTests.cs | 26 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 5 ++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index ed8ca04743..a375043309 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -81,7 +81,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual bool IsShared { - get { throw new NotImplementedException(); } + get { return method.IsStatic; } } public virtual bool MustImplement { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index dc7ef7ec34..a239941969 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -70,6 +70,11 @@ namespace PackageManagement.Tests.EnvDTE helper.AddReturnTypeToMethod(type); } + void MakeMethodStatic() + { + helper.MakeMethodStatic(); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -272,5 +277,26 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(vsCMFunction.vsCMFunctionConstructor, kind); } + + [Test] + public void IsShared_StaticMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodStatic(); + + bool shared = codeFunction.IsShared; + + Assert.IsTrue(shared); + } + + [Test] + public void IsShared_MethodIsNotStatic_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool shared = codeFunction.IsShared; + + Assert.IsFalse(shared); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index 946e6e8400..a8cdd6d4c7 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -118,5 +118,10 @@ namespace PackageManagement.Tests.Helpers Method.Stub(m => m.ReturnType).Return(returnTypeHelper.ReturnType); } + + public void MakeMethodStatic() + { + Method.Stub(m => m.IsStatic).Return(true); + } } } From b1e90b14ef65d9a3349c16a1b34da10b5748dd52 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 14:11:51 +0100 Subject: [PATCH 16/53] Implement EnvDTE.CodeFunction.MustImplement Returns true if the method is abstract. --- .../Project/Src/EnvDTE/CodeFunction.cs | 2 +- .../Test/Src/EnvDTE/CodeFunctionTests.cs | 26 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 5 ++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index a375043309..018a2b9eff 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -85,7 +85,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual bool MustImplement { - get { throw new NotImplementedException(); } + get { return method.IsAbstract; } } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index a239941969..694fa759f4 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -75,6 +75,11 @@ namespace PackageManagement.Tests.EnvDTE helper.MakeMethodStatic(); } + void MakeMethodAbstract() + { + helper.MakeMethodAbstract(); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -298,5 +303,26 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsFalse(shared); } + + [Test] + public void MustImplement_AbstractMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodAbstract(); + + bool mustImplement = codeFunction.MustImplement; + + Assert.IsTrue(mustImplement); + } + + [Test] + public void MustImplement_MethodIsNotAbstract_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool mustImplement = codeFunction.MustImplement; + + Assert.IsFalse(mustImplement); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index a8cdd6d4c7..49d390e355 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -123,5 +123,10 @@ namespace PackageManagement.Tests.Helpers { Method.Stub(m => m.IsStatic).Return(true); } + + public void MakeMethodAbstract() + { + Method.Stub(m => m.IsAbstract).Return(true); + } } } From 02bd3e331dbdd0cd67a530559e7ac9c0fd346a52 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 14:18:05 +0100 Subject: [PATCH 17/53] Implement EnvDTE.CodeFunction.CanOverride --- .../Project/Src/EnvDTE/CodeFunction.cs | 2 +- .../Test/Src/EnvDTE/CodeFunctionTests.cs | 37 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 5 +++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index 018a2b9eff..d7cd074f5a 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -64,7 +64,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual bool CanOverride { - get { throw new NotImplementedException(); } + get { return MustImplement || method.IsVirtual; } set { throw new NotImplementedException(); } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index 694fa759f4..a1657beea8 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -80,6 +80,11 @@ namespace PackageManagement.Tests.EnvDTE helper.MakeMethodAbstract(); } + void MakeMethodVirtual() + { + helper.MakeMethodVirtual(); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -324,5 +329,37 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsFalse(mustImplement); } + + [Test] + public void CanOverride_AbstractMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodAbstract(); + + bool canOverride = codeFunction.CanOverride; + + Assert.IsTrue(canOverride); + } + + [Test] + public void CanOverride_MethodIsNotAbstractOrVirtual_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool canOverride = codeFunction.CanOverride; + + Assert.IsFalse(canOverride); + } + + [Test] + public void CanOverride_VirtualMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodVirtual(); + + bool canOverride = codeFunction.CanOverride; + + Assert.IsTrue(canOverride); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index 49d390e355..e5db5e579c 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -128,5 +128,10 @@ namespace PackageManagement.Tests.Helpers { Method.Stub(m => m.IsAbstract).Return(true); } + + public void MakeMethodVirtual() + { + Method.Stub(m => m.IsVirtual).Return(true); + } } } From b17aa07a6dc74e093eca93c1767034c249ed61fd Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 14:30:18 +0100 Subject: [PATCH 18/53] Implement EnvDTE.CodeFunction.Attributes The T4MVC template checks method attributes. --- .../Project/Src/EnvDTE/CodeFunction.cs | 2 +- .../Test/Src/EnvDTE/CodeFunctionTests.cs | 18 ++++++++++++++++++ .../Test/Src/Helpers/AttributeHelper.cs | 11 +++++++++-- .../Test/Src/Helpers/ClassHelper.cs | 4 ++-- .../Test/Src/Helpers/MethodHelper.cs | 7 +++++++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index d7cd074f5a..4f0b396321 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -60,7 +60,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual CodeElements Attributes { - get { throw new NotImplementedException(); } + get { return new CodeAttributes(method); } } public virtual bool CanOverride { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index a1657beea8..b46f6993fe 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -85,6 +85,11 @@ namespace PackageManagement.Tests.EnvDTE helper.MakeMethodVirtual(); } + void AddMethodAttribute(string attributeTypeName) + { + helper.AddAttributeToMethod(attributeTypeName); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -361,5 +366,18 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsTrue(canOverride); } + + [Test] + public void Attributes_MethodHasOneAttribute_ReturnsOneAttribute() + { + CreatePublicFunction("MyClass.MyFunction"); + AddMethodAttribute("System.ObsoleteAttribute"); + + CodeElements attributes = codeFunction.Attributes; + + CodeAttribute2 attribute = attributes.FirstCodeAttribute2OrDefault(); + Assert.AreEqual(1, attributes.Count); + Assert.AreEqual("System.ObsoleteAttribute", attribute.FullName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs index 0f68b2e0aa..adcaa3af8f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs @@ -43,11 +43,18 @@ namespace PackageManagement.Tests.Helpers NamedArguments.Add(name, value); } - public void AddAttributeToClass(IClass @class) + public void AddAttributeToClass(IClass c) { var attributes = new List(); attributes.Add(Attribute); - @class.Stub(c => c.Attributes).Return(attributes); + c.Stub(item => item.Attributes).Return(attributes); + } + + public void AddAttributeToMethod(IMethod method) + { + var attributes = new List(); + attributes.Add(Attribute); + method.Stub(m => m.Attributes).Return(attributes); } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 124e4853a2..ba169b6806 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -33,10 +33,10 @@ namespace PackageManagement.Tests.Helpers Class.Stub(c => c.CompilationUnit).Return(CompilationUnitHelper.CompilationUnit); } - public void AddAttributeToClass(string name) + public void AddAttributeToClass(string attributeTypeName) { var attributeHelper = new AttributeHelper(); - attributeHelper.CreateAttribute(name); + attributeHelper.CreateAttribute(attributeTypeName); attributeHelper.AddAttributeToClass(Class); } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index e5db5e579c..9e194fe539 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -133,5 +133,12 @@ namespace PackageManagement.Tests.Helpers { Method.Stub(m => m.IsVirtual).Return(true); } + + public void AddAttributeToMethod(string attributeTypeName) + { + var attributeHelper = new AttributeHelper(); + attributeHelper.CreateAttribute(attributeTypeName); + attributeHelper.AddAttributeToMethod(Method); + } } } From a315a11f4d63887792dc427fd128361eae326508 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 14:38:26 +0100 Subject: [PATCH 19/53] Return EnvDTE.CodeFunction2 instances from EnvDTE.CodeClass2.Members. The T4MVC assumes the class methods are instances of the CodeFunction2 type. --- .../PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs | 4 +++- .../PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs | 2 +- .../Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs | 2 +- .../Test/Src/Helpers/CodeElementsExtensions.cs | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs index b0a0a20fff..64f0db144b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs @@ -2,12 +2,14 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using ICSharpCode.SharpDevelop.Dom; namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeFunction2 : CodeFunction { - public CodeFunction2() + public CodeFunction2(IMethod method) + : base(method) { } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs index fa352035ab..d2c6ab10dd 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE void AddMethod(IMethod method) { - AddCodeElement(new CodeFunction(method)); + AddCodeElement(new CodeFunction2(method)); } void AddField(IField field) diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index fc0f0794f8..a9553b652a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -211,7 +211,7 @@ namespace PackageManagement.Tests.EnvDTE AddMethodToClass("MyClass.MyMethod"); CodeElements codeElements = codeClass.Members; - CodeFunction codeFunction = codeElements.FirstCodeFunctionOrDefault(); + CodeFunction2 codeFunction = codeElements.FirstCodeFunction2OrDefault(); Assert.AreEqual(1, codeElements.Count); Assert.AreEqual("MyMethod", codeFunction.Name); diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs index 87e6749f84..ca0b2ca1bc 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs @@ -24,9 +24,9 @@ namespace PackageManagement.Tests.Helpers return ToList(codeElements).FirstOrDefault(); } - public static CodeFunction FirstCodeFunctionOrDefault(this CodeElements codeElements) + public static CodeFunction2 FirstCodeFunction2OrDefault(this CodeElements codeElements) { - return codeElements.FirstOrDefault() as CodeFunction; + return codeElements.FirstOrDefault() as CodeFunction2; } public static CodeClass2 FirstCodeClass2OrDefault(this CodeElements codeElements) From 32d5d39e8beab93763a4cc29ca961e38fa8a9a29 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 15:05:42 +0100 Subject: [PATCH 20/53] Implement EnvDTE.CodeFunction2.OverrideKind The T4MVC template checks that a method is an overridden method. --- .../Project/Src/EnvDTE/CodeFunction.cs | 23 ++--- .../Project/Src/EnvDTE/CodeFunction2.cs | 18 +++- .../Project/Src/EnvDTE/vsCMOverrideKind.cs | 7 +- .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/EnvDTE/CodeFunction2Tests.cs | 99 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 15 +++ 6 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index 4f0b396321..469ed23c4d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -8,7 +8,6 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeFunction : CodeElement { - IMethodOrProperty method; IDocumentLoader documentLoader; public CodeFunction(IMethod method) @@ -19,7 +18,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE public CodeFunction(IMethod method, IDocumentLoader documentLoader) : base(method) { - this.method = method; + this.Method = method; this.documentLoader = documentLoader; } @@ -32,6 +31,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { } + protected IMethodOrProperty Method { get; private set; } + public override vsCMElement Kind { get { return vsCMElement.vsCMElementFunction; } } @@ -43,28 +44,28 @@ namespace ICSharpCode.PackageManagement.EnvDTE public override TextPoint GetStartPoint() { - return new TextPoint(method.GetStartPosition(), documentLoader); + return new TextPoint(Method.GetStartPosition(), documentLoader); } public override TextPoint GetEndPoint() { - return new TextPoint(method.GetEndPosition(), documentLoader); + return new TextPoint(Method.GetEndPosition(), documentLoader); } public virtual CodeElements Parameters { - get { return new CodeParameters(method.ProjectContent, method.Parameters); } + get { return new CodeParameters(Method.ProjectContent, Method.Parameters); } } public virtual CodeTypeRef2 Type { - get { return new CodeTypeRef2(method.ProjectContent, this, method.ReturnType); } + get { return new CodeTypeRef2(Method.ProjectContent, this, Method.ReturnType); } } public virtual CodeElements Attributes { - get { return new CodeAttributes(method); } + get { return new CodeAttributes(Method); } } public virtual bool CanOverride { - get { return MustImplement || method.IsVirtual; } + get { return MustImplement || Method.IsVirtual; } set { throw new NotImplementedException(); } } @@ -74,18 +75,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE vsCMFunction GetFunctionKind() { - if (method.IsConstructor()) { + if (Method.IsConstructor()) { return vsCMFunction.vsCMFunctionConstructor; } return vsCMFunction.vsCMFunctionFunction; } public virtual bool IsShared { - get { return method.IsStatic; } + get { return Method.IsStatic; } } public virtual bool MustImplement { - get { return method.IsAbstract; } + get { return Method.IsAbstract; } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs index 64f0db144b..fe0fdde9a5 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs @@ -18,7 +18,23 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual vsCMOverrideKind OverrideKind { - get { throw new NotImplementedException(); } + get { return GetOverrideKind(); } + } + + vsCMOverrideKind GetOverrideKind() + { + if (Method.IsAbstract) { + return vsCMOverrideKind.vsCMOverrideKindAbstract; + } else if (Method.IsVirtual) { + return vsCMOverrideKind.vsCMOverrideKindVirtual; + } else if (Method.IsOverride) { + return vsCMOverrideKind.vsCMOverrideKindOverride; + } else if (Method.IsSealed) { + return vsCMOverrideKind.vsCMOverrideKindSealed; + } else if (Method.IsNew) { + return vsCMOverrideKind.vsCMOverrideKindNew; + } + return vsCMOverrideKind.vsCMOverrideKindNone; } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs index 8491407ced..83d54ec1a1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs @@ -7,6 +7,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMOverrideKind { - vsCMOverrideKindOverride = 4 + vsCMOverrideKindNone = 0, + vsCMOverrideKindAbstract = 1, + vsCMOverrideKindVirtual = 2, + vsCMOverrideKindOverride = 4, + vsCMOverrideKindNew = 8, + vsCMOverrideKindSealed = 16 } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index 6bf1fe435b..a3f48db65b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -82,6 +82,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs new file mode 100644 index 0000000000..409b3c6da0 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs @@ -0,0 +1,99 @@ +// 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.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class CodeFunction2Tests + { + CodeFunction2 codeFunction; + MethodHelper helper; + + [SetUp] + public void Init() + { + helper = new MethodHelper(); + } + + void CreatePublicFunction(string name) + { + helper.CreatePublicMethod(name); + CreateFunction(); + } + + void CreateFunction() + { + codeFunction = new CodeFunction2(helper.Method); + } + + [Test] + public void OverrideKind_OrdinaryMethod_ReturnsNone() + { + CreatePublicFunction("MyClass.MyFunction"); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindNone, kind); + } + + [Test] + public void OverrideKind_AbstractMethod_ReturnsAbstract() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodAbstract(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindAbstract, kind); + } + + [Test] + public void OverrideKind_VirtualMethod_ReturnsVirtual() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodVirtual(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindVirtual, kind); + } + + [Test] + public void OverrideKind_MethodOverride_ReturnsOverride() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodOverride(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindOverride, kind); + } + + [Test] + public void OverrideKind_SealedMethod_ReturnsSealed() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodSealed(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindSealed, kind); + } + + [Test] + public void OverrideKind_MethodHiddenByNewKeyword_ReturnsNew() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodNewOverride(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindNew, kind); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index 9e194fe539..f7052cbd20 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -140,5 +140,20 @@ namespace PackageManagement.Tests.Helpers attributeHelper.CreateAttribute(attributeTypeName); attributeHelper.AddAttributeToMethod(Method); } + + public void MakeMethodOverride() + { + Method.Stub(m => m.IsOverride).Return(true); + } + + public void MakeMethodSealed() + { + Method.Stub(m => m.IsSealed).Return(true); + } + + public void MakeMethodNewOverride() + { + Method.Stub(m => m.IsNew).Return(true); + } } } From 1e6d363c41ced87d8b317428931f8b5170265197 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 15:13:45 +0100 Subject: [PATCH 21/53] Fix CodeFunction.CanOverride returning false for overridden methods. --- .../Project/Src/EnvDTE/CodeFunction.cs | 2 +- .../Test/Src/EnvDTE/CodeFunctionTests.cs | 20 +++++++------------ .../Test/Src/Helpers/MethodHelper.cs | 5 +++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index 469ed23c4d..5e95b16e1b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -65,7 +65,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual bool CanOverride { - get { return MustImplement || Method.IsVirtual; } + get { return Method.IsOverridable; } set { throw new NotImplementedException(); } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index b46f6993fe..e8a36cf19a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -90,6 +90,11 @@ namespace PackageManagement.Tests.EnvDTE helper.AddAttributeToMethod(attributeTypeName); } + void MakeMethodOverridable() + { + helper.MakeMethodOverridable(); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -336,10 +341,10 @@ namespace PackageManagement.Tests.EnvDTE } [Test] - public void CanOverride_AbstractMethod_ReturnsTrue() + public void CanOverride_MethodIsOverridable_ReturnsTrue() { CreatePublicFunction("MyClass.MyFunction"); - MakeMethodAbstract(); + MakeMethodOverridable(); bool canOverride = codeFunction.CanOverride; @@ -356,17 +361,6 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsFalse(canOverride); } - [Test] - public void CanOverride_VirtualMethod_ReturnsTrue() - { - CreatePublicFunction("MyClass.MyFunction"); - MakeMethodVirtual(); - - bool canOverride = codeFunction.CanOverride; - - Assert.IsTrue(canOverride); - } - [Test] public void Attributes_MethodHasOneAttribute_ReturnsOneAttribute() { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index f7052cbd20..98a214e27e 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -155,5 +155,10 @@ namespace PackageManagement.Tests.Helpers { Method.Stub(m => m.IsNew).Return(true); } + + public void MakeMethodOverridable() + { + Method.Stub(m => m.IsOverridable).Return(true); + } } } From 8bab34c5fb9aebbccc03907792e8cd76a315a0fa Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 15:56:55 +0100 Subject: [PATCH 22/53] Implemented EnvDTE.CodeFunction2.IsGeneric The T4MVC template ignores controller methods that are generic. --- .../Project/Src/EnvDTE/CodeFunction2.cs | 2 +- .../Src/IMethodOrPropertyExtensions.cs | 9 ++++++ .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/EnvDTE/CodeFunction2Tests.cs | 32 +++++++++++++++++++ .../Test/Src/Helpers/MethodHelper.cs | 18 +++++++++++ .../Test/Src/Helpers/TypeParameterHelper.cs | 32 +++++++++++++++++++ 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs index fe0fdde9a5..6b7cf2f682 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual bool IsGeneric { - get { throw new NotImplementedException(); } + get { return Method.HasTypeParameters(); } } public virtual vsCMOverrideKind OverrideKind { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs index e81b599bd0..fb688063b8 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs @@ -34,5 +34,14 @@ namespace ICSharpCode.PackageManagement } return false; } + + public static bool HasTypeParameters(this IMethodOrProperty methodOrProperty) + { + var method = methodOrProperty as IMethod; + if ((method != null) && (method.TypeParameters != null)) { + return method.TypeParameters.Count > 0; + } + return false; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index a3f48db65b..39a806b22d 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -122,6 +122,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs index 409b3c6da0..ce4cac4b7f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs @@ -95,5 +95,37 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindNew, kind); } + + [Test] + public void IsGeneric_MethodHasTypeParameter_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.AddTypeParameter("TResult"); + + bool generic = codeFunction.IsGeneric; + + Assert.IsTrue(generic); + } + + [Test] + public void IsGeneric_MethodHasTypeParameters_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.NoTypeParameters(); + + bool generic = codeFunction.IsGeneric; + + Assert.IsFalse(generic); + } + + [Test] + public void IsGeneric_MethodTypeParametersIsNull_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool generic = codeFunction.IsGeneric; + + Assert.IsFalse(generic); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index 98a214e27e..59e502e6ff 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using ICSharpCode.SharpDevelop.Dom; using Rhino.Mocks; @@ -160,5 +161,22 @@ namespace PackageManagement.Tests.Helpers { Method.Stub(m => m.IsOverridable).Return(true); } + + public void AddTypeParameter(string name) + { + var typeParameterHelper = new TypeParameterHelper(); + typeParameterHelper.SetName(name); + AddTypeParameters(typeParameterHelper.TypeParameterToList()); + } + + public void AddTypeParameters(List typeParameters) + { + Method.Stub(m => m.TypeParameters).Return(typeParameters); + } + + public void NoTypeParameters() + { + AddTypeParameters(new List()); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs new file mode 100644 index 0000000000..f76f34f8e5 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs @@ -0,0 +1,32 @@ +// 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 System.Collections.Generic; +using ICSharpCode.SharpDevelop.Dom; +using Rhino.Mocks; + +namespace PackageManagement.Tests.Helpers +{ + public class TypeParameterHelper + { + public ITypeParameter TypeParameter; + + public TypeParameterHelper() + { + TypeParameter = MockRepository.GenerateMock(); + } + + public void SetName(string name) + { + TypeParameter.Stub(tp => tp.Name); + } + + public List TypeParameterToList() + { + var parameters = new List(); + parameters.Add(TypeParameter); + return parameters; + } + } +} From b80bfb80b6247d4a28c37a89f011ca6977e0c276 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 17:54:23 +0100 Subject: [PATCH 23/53] Implement EnvDTE.CodeParameter2.ParameterKind The T4MVC template checks whether a parameter is optional so it can determine which controller action methods can be called without any parameters. --- .../Project/PackageManagement.csproj | 1 + .../Project/Src/EnvDTE/CodeParameter.cs | 9 +- .../Project/Src/EnvDTE/CodeParameter2.cs | 18 +++- .../Src/EnvDTE/IParameterExtensions.cs | 16 ++++ .../Project/Src/EnvDTE/vsCMParameterKind.cs | 7 +- .../Test/PackageManagement.Tests.csproj | 2 + .../Test/Src/EnvDTE/CodeParameter2Tests.cs | 93 +++++++++++++++++++ .../Test/Src/EnvDTE/CodeParameterTests.cs | 10 +- .../Test/Src/Helpers/ParameterHelper.cs | 44 +++++++++ 9 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index 61e8ad740e..0bf85fb523 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -127,6 +127,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs index 22e0e9b2b8..6613c1ee6e 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs @@ -9,24 +9,25 @@ namespace ICSharpCode.PackageManagement.EnvDTE public class CodeParameter : CodeElement { IProjectContent projectContent; - IParameter parameter; public CodeParameter(IProjectContent projectContent, IParameter parameter) { this.projectContent = projectContent; - this.parameter = parameter; + this.Parameter = parameter; } + protected IParameter Parameter { get; private set; } + public override vsCMElement Kind { get { return vsCMElement.vsCMElementParameter; } } public override string Name { - get { return parameter.Name; } + get { return Parameter.Name; } } public virtual CodeTypeRef2 Type { - get { return new CodeTypeRef2(projectContent, this, parameter.ReturnType); } + get { return new CodeTypeRef2(projectContent, this, Parameter.ReturnType); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs index 721805894b..1d12478ee2 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs @@ -14,7 +14,23 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual vsCMParameterKind ParameterKind { - get { throw new NotImplementedException(); } + get { return GetParameterKind(); } + } + + vsCMParameterKind GetParameterKind() + { + if (Parameter.IsOptional) { + return vsCMParameterKind.vsCMParameterKindOptional; + } else if (Parameter.IsOut) { + return vsCMParameterKind.vsCMParameterKindOut; + } else if (Parameter.IsRef) { + return vsCMParameterKind.vsCMParameterKindRef; + } else if (Parameter.IsParams) { + return vsCMParameterKind.vsCMParameterKindParamArray; + } else if (Parameter.IsIn()) { + return vsCMParameterKind.vsCMParameterKindIn; + } + return vsCMParameterKind.vsCMParameterKindNone; } public virtual CodeElements Attributes { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs new file mode 100644 index 0000000000..89b949c521 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs @@ -0,0 +1,16 @@ +// 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; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class IParameterExtensions + { + public static bool IsIn(this IParameter parameter) + { + return (parameter.Modifiers & ParameterModifiers.In) == ParameterModifiers.In; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs index 6959e8d1d0..8ffd82a8d2 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs @@ -7,6 +7,11 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMParameterKind { - vsCMParameterKindOptional = 8 + vsCMParameterKindNone = 0, + vsCMParameterKindIn = 1, + vsCMParameterKindRef = 2, + vsCMParameterKindOut = 4, + vsCMParameterKindOptional = 8, + vsCMParameterKindParamArray = 16 } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index 39a806b22d..f23b019105 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -88,6 +88,7 @@ + @@ -112,6 +113,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs new file mode 100644 index 0000000000..ad0b6d934d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs @@ -0,0 +1,93 @@ +// 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.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class CodeParameter2Tests + { + ParameterHelper helper; + CodeParameter2 parameter; + + [SetUp] + public void Init() + { + helper = new ParameterHelper(); + } + + void CreateParameter() + { + parameter = new CodeParameter2(null, helper.Parameter); + } + + [Test] + public void ParameterKind_NormalParameter_ReturnsNone() + { + CreateParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindNone, kind); + } + + [Test] + public void ParameterKind_OptionalParameter_ReturnsOptional() + { + CreateParameter(); + helper.MakeOptionalParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindOptional, kind); + } + + [Test] + public void ParameterKind_OutParameter_ReturnsOut() + { + CreateParameter(); + helper.MakeOutParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindOut, kind); + } + + [Test] + public void ParameterKind_RefParameter_ReturnsRef() + { + CreateParameter(); + helper.MakeRefParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindRef, kind); + } + + [Test] + public void ParameterKind_ParamArrayParameter_ReturnsParamArray() + { + CreateParameter(); + helper.MakeParamArrayParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindParamArray, kind); + } + + [Test] + public void ParameterKind_InParameter_ReturnsIn() + { + CreateParameter(); + helper.MakeInParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindIn, kind); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs index 5fd217f712..4843a65012 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs @@ -4,17 +4,25 @@ using System; using ICSharpCode.PackageManagement.EnvDTE; using NUnit.Framework; +using PackageManagement.Tests.Helpers; namespace PackageManagement.Tests.EnvDTE { [TestFixture] public class CodeParameterTests { + ParameterHelper helper; CodeParameter parameter; + [SetUp] + public void Init() + { + helper = new ParameterHelper(); + } + void CreateParameter() { - parameter = new CodeParameter(null, null); + parameter = new CodeParameter(null, helper.Parameter); } [Test] diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs new file mode 100644 index 0000000000..e3a4806db8 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs @@ -0,0 +1,44 @@ +// 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 Rhino.Mocks; + +namespace PackageManagement.Tests.Helpers +{ + public class ParameterHelper + { + public IParameter Parameter; + + public ParameterHelper() + { + Parameter = MockRepository.GenerateStub(); + } + + public void MakeOptionalParameter() + { + Parameter.Stub(p => p.IsOptional).Return(true); + } + + public void MakeOutParameter() + { + Parameter.Stub(p => p.IsOut).Return(true); + } + + public void MakeRefParameter() + { + Parameter.Stub(p => p.IsRef).Return(true); + } + + public void MakeParamArrayParameter() + { + Parameter.Stub(p => p.IsParams).Return(true); + } + + public void MakeInParameter() + { + Parameter.Stub(p => p.Modifiers).Return(ParameterModifiers.In); + } + } +} From 358fbf071ba4cc8850ae1027b3ec5c4ae61f8f3b Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 18:18:55 +0100 Subject: [PATCH 24/53] Implement EnvDTE.CodeParameter.Attributes The T4MVC template looks for the MVC BindAttribute on method parameters in order to get the prefix. --- .../Project/Src/EnvDTE/CodeAttributes.cs | 19 +++++++++++++------ .../Project/Src/EnvDTE/CodeParameter.cs | 4 ++++ .../Project/Src/EnvDTE/CodeParameter2.cs | 4 ---- .../Test/Src/EnvDTE/CodeParameterTests.cs | 13 +++++++++++++ .../Test/Src/Helpers/AttributeHelper.cs | 7 +++++++ .../Test/Src/Helpers/ParameterHelper.cs | 7 +++++++ 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs index a3bd7761ef..a41cd3d50b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs @@ -11,17 +11,24 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeAttributes : CodeElementsList { - IEntity entity; - public CodeAttributes(IEntity entity) + : this(entity.Attributes) + { + } + + public CodeAttributes(IParameter parameter) + : this(parameter.Attributes) + { + } + + public CodeAttributes(IEnumerable attributes) { - this.entity = entity; - GetAttributes(); + AddAttributes(attributes); } - void GetAttributes() + void AddAttributes(IEnumerable attributes) { - foreach (IAttribute attribute in entity.Attributes) { + foreach (IAttribute attribute in attributes) { AddAttribute(attribute); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs index 6613c1ee6e..a8c16b5ad4 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs @@ -29,5 +29,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual CodeTypeRef2 Type { get { return new CodeTypeRef2(projectContent, this, Parameter.ReturnType); } } + + public virtual CodeElements Attributes { + get { return new CodeAttributes(Parameter); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs index 1d12478ee2..40b78f73ec 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs @@ -32,9 +32,5 @@ namespace ICSharpCode.PackageManagement.EnvDTE } return vsCMParameterKind.vsCMParameterKindNone; } - - public virtual CodeElements Attributes { - get { throw new NotImplementedException(); } - } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs index 4843a65012..f596afbfe9 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs @@ -34,5 +34,18 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(vsCMElement.vsCMElementParameter, kind); } + + [Test] + public void Attributes_ParameterHasOneAttribute_ReturnsOneAttribute() + { + CreateParameter(); + helper.AddAttributeToParameter("System.Web.Mvc.BindAttribute"); + + CodeElements attributes = parameter.Attributes; + + CodeAttribute2 attribute = parameter.Attributes.FirstCodeAttribute2OrDefault(); + Assert.AreEqual(1, attributes.Count); + Assert.AreEqual("System.Web.Mvc.BindAttribute", attribute.FullName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs index adcaa3af8f..1f0fbde93b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs @@ -56,5 +56,12 @@ namespace PackageManagement.Tests.Helpers attributes.Add(Attribute); method.Stub(m => m.Attributes).Return(attributes); } + + public void AddAttributeToParameter(IParameter parameter) + { + var attributes = new List(); + attributes.Add(Attribute); + parameter.Stub(p => p.Attributes).Return(attributes); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs index e3a4806db8..85efb03c0d 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs @@ -40,5 +40,12 @@ namespace PackageManagement.Tests.Helpers { Parameter.Stub(p => p.Modifiers).Return(ParameterModifiers.In); } + + public void AddAttributeToParameter(string attributeTypeName) + { + var attributeHelper = new AttributeHelper(); + attributeHelper.CreateAttribute(attributeTypeName); + attributeHelper.AddAttributeToParameter(Parameter); + } } } From d67c82e1f18a4f2a4b6c2f66dfd16e97c45a65ab Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 19:22:04 +0100 Subject: [PATCH 25/53] Implement EnvDTE.ProjectItem.Document The T4MVC template checks the ProjectItem.Document property to see if it has been opened. --- .../Project/Src/EnvDTE/Document.cs | 5 ++- .../Project/Src/EnvDTE/Project.cs | 5 +++ .../Project/Src/EnvDTE/ProjectItem.cs | 16 +++++++-- .../Src/IPackageManagementFileService.cs | 1 + .../Src/PackageManagementFileService.cs | 9 +++++ .../Test/Src/EnvDTE/ProjectItemTests.cs | 36 +++++++++++++++++++ .../Test/Src/Helpers/FakeFileService.cs | 14 ++++++++ 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs index 6784ee97bc..190567296b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs @@ -7,13 +7,16 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class Document { - public Document() + public Document(string fileName) { + this.FullName = fileName; } public virtual bool Saved { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } + + public string FullName { get; private set; } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index f82e536f71..0d879ef15b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -289,5 +289,10 @@ namespace ICSharpCode.PackageManagement.EnvDTE } return null; } + + internal bool IsFileOpen(string fileName) + { + return fileService.IsOpen(fileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index 747dee441b..8dd6455b33 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -167,11 +167,23 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual string FileNames(short index) { - return projectItem.FileName; + return FileName; + } + + string FileName { + get { return projectItem.FileName; } } public Document Document { - get { throw new NotImplementedException(); } + get { return GetOpenDocument(); } + } + + Document GetOpenDocument() + { + if (ContainingProject.IsFileOpen(FileName)) { + return new Document(FileName); + } + return null; } public Window Open(string viewKind) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs index 0dc8415f96..efce0ed11c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs @@ -10,6 +10,7 @@ namespace ICSharpCode.PackageManagement { void RemoveFile(string path); void RemoveDirectory(string path); + bool IsOpen(string fileName); void OpenFile(string fileName); void CopyFile(string oldFileName, string newFileName); bool FileExists(string fileName); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs index 5545777835..b65fd8ddf9 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs @@ -41,6 +41,15 @@ namespace ICSharpCode.PackageManagement } } + public bool IsOpen(string fileName) + { + if (WorkbenchSingleton.InvokeRequired) { + return WorkbenchSingleton.SafeThreadFunction(() => IsOpen(fileName)); + } else { + return FileService.IsOpen(fileName); + } + } + public void CopyFile(string oldFileName, string newFileName) { if (WorkbenchSingleton.InvokeRequired) { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index 6d4f9d9d0f..309d0e601f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -5,7 +5,9 @@ using System; using System.Collections; using System.Collections.Generic; using ICSharpCode.PackageManagement.EnvDTE; +using ICSharpCode.SharpDevelop.Gui; using DTE = ICSharpCode.PackageManagement.EnvDTE; +using Rhino.Mocks; using NUnit.Framework; using PackageManagement.Tests.Helpers; @@ -27,6 +29,12 @@ namespace PackageManagement.Tests.EnvDTE fakeFileService = project.FakeFileService; } + void OpenFileInSharpDevelop(string fileName) + { + IViewContent view = MockRepository.GenerateStub(); + fakeFileService.AddOpenView(view, fileName); + } + [Test] public void ProjectItems_ProjectHasOneFileInsideSrcDirectory_ReturnsOneFileForSrcDirectory() { @@ -230,5 +238,33 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(@"d:\projects\MyProject\src", fileName); } + + [Test] + public void Document_ProjectItemNotOpenInSharpDevelop_ReturnsNull() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + + Document document = item.Document; + + Assert.IsNull(document); + } + + [Test] + public void Document_ProjectItemOpenInSharpDevelop_ReturnsOpenDocumentForFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + string projectItemFileName = @"d:\projects\MyProject\program.cs"; + OpenFileInSharpDevelop(projectItemFileName); + + Document document = item.Document; + + Assert.AreEqual(projectItemFileName, document.FullName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs index 0eb42f8e12..1ff7a6430c 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; + using ICSharpCode.PackageManagement; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; namespace PackageManagement.Tests.Helpers @@ -123,5 +125,17 @@ namespace PackageManagement.Tests.Helpers FileNamePassedToGetCompilationUnit = fileName; return CompilationUnitToReturnFromGetCompilationUnit; } + + public bool IsOpen(string fileName) + { + return openViews.ContainsKey(fileName); + } + + Dictionary openViews = new Dictionary(); + + public void AddOpenView(IViewContent view, string fileName) + { + openViews.Add(fileName, view); + } } } From 69ccf0af4549df80d7d658a0fa088a68d89f4af8 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 19:55:48 +0100 Subject: [PATCH 26/53] Implement EnvDTE.Document.Saved When T4MVC is configured to always keep its template unsaved then it uses Document.Saved to false each time it is run. --- .../Project/Src/EnvDTE/Document.cs | 10 +++- .../Project/Src/EnvDTE/Project.cs | 6 +- .../Project/Src/EnvDTE/ProjectItem.cs | 6 +- .../Src/IPackageManagementFileService.cs | 3 +- .../Src/PackageManagementFileService.cs | 6 +- .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/EnvDTE/DocumentTests.cs | 59 +++++++++++++++++++ .../Test/Src/EnvDTE/ProjectItemTests.cs | 43 +++++++++++++- .../Test/Src/Helpers/FakeFileService.cs | 13 ++-- 9 files changed, 129 insertions(+), 18 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs index 190567296b..68ca69601d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs @@ -2,19 +2,23 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.PackageManagement.EnvDTE { public class Document { - public Document(string fileName) + IViewContent view; + + public Document(string fileName, IViewContent view) { this.FullName = fileName; + this.view = view; } public virtual bool Saved { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } + get { return !view.IsDirty; } + set { view.PrimaryFile.IsDirty = !value; } } public string FullName { get; private set; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index 0d879ef15b..5b2ae299cb 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; + using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using Microsoft.Build.Construction; using SD = ICSharpCode.SharpDevelop.Project; @@ -290,9 +292,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE return null; } - internal bool IsFileOpen(string fileName) + internal IViewContent GetOpenFile(string fileName) { - return fileService.IsOpen(fileName); + return fileService.GetOpenFile(fileName); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index 8dd6455b33..c06af27178 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -7,6 +7,7 @@ using System.IO; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using SD = ICSharpCode.SharpDevelop.Project; @@ -180,8 +181,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE Document GetOpenDocument() { - if (ContainingProject.IsFileOpen(FileName)) { - return new Document(FileName); + IViewContent view = ContainingProject.GetOpenFile(FileName); + if (view != null) { + return new Document(FileName, view); } return null; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs index efce0ed11c..3dccaa8318 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs @@ -3,6 +3,7 @@ using System; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.PackageManagement { @@ -10,8 +11,8 @@ namespace ICSharpCode.PackageManagement { void RemoveFile(string path); void RemoveDirectory(string path); - bool IsOpen(string fileName); void OpenFile(string fileName); + IViewContent GetOpenFile(string fileName); void CopyFile(string oldFileName, string newFileName); bool FileExists(string fileName); string[] GetFiles(string path); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs index b65fd8ddf9..902c0b7a5f 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs @@ -41,12 +41,12 @@ namespace ICSharpCode.PackageManagement } } - public bool IsOpen(string fileName) + public IViewContent GetOpenFile(string fileName) { if (WorkbenchSingleton.InvokeRequired) { - return WorkbenchSingleton.SafeThreadFunction(() => IsOpen(fileName)); + return WorkbenchSingleton.SafeThreadFunction(() => GetOpenFile(fileName)); } else { - return FileService.IsOpen(fileName); + return FileService.GetOpenFile(fileName); } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index f23b019105..9ea4866e47 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -95,6 +95,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs new file mode 100644 index 0000000000..0e85ea4dc0 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs @@ -0,0 +1,59 @@ +// 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.EnvDTE; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using NUnit.Framework; +using Rhino.Mocks; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class DocumentTests + { + IViewContent view; + Document document; + OpenedFile openedFile; + + [SetUp] + public void Init() + { + openedFile = MockRepository.GenerateStub(); + view = MockRepository.GenerateStub(); + view.Stub(v => v.PrimaryFile).Return(openedFile); + } + + void CreateDocument(string fileName) + { + document = new Document(fileName, view); + } + + void OpenFileIsDirty() + { + openedFile.IsDirty = true; + } + + [Test] + public void Saved_SetToTrue_OpenFileIsDirtySetToFalse() + { + CreateDocument(@"d:\projects\MyProject\program.cs"); + OpenFileIsDirty(); + + document.Saved = true; + + Assert.IsFalse(openedFile.IsDirty); + } + + [Test] + public void Saved_SetToFalse_OpenFileIsDirtySetToTrue() + { + CreateDocument(@"d:\projects\MyProject\program.cs"); + + document.Saved = false; + + Assert.IsTrue(openedFile.IsDirty); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index 309d0e601f..d0251dc2cf 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -29,9 +29,20 @@ namespace PackageManagement.Tests.EnvDTE fakeFileService = project.FakeFileService; } - void OpenFileInSharpDevelop(string fileName) + void OpenSavedFileInSharpDevelop(string fileName) + { + OpenFileInSharpDevelop(fileName, dirty: false); + } + + void OpenUnsavedFileInSharpDevelop(string fileName) + { + OpenFileInSharpDevelop(fileName, dirty: true); + } + + void OpenFileInSharpDevelop(string fileName, bool dirty) { IViewContent view = MockRepository.GenerateStub(); + view.Stub(v => v.IsDirty).Return(dirty); fakeFileService.AddOpenView(view, fileName); } @@ -260,11 +271,39 @@ namespace PackageManagement.Tests.EnvDTE msbuildProject.AddFile(@"program.cs"); ProjectItem item = projectItems.Item("program.cs"); string projectItemFileName = @"d:\projects\MyProject\program.cs"; - OpenFileInSharpDevelop(projectItemFileName); + OpenSavedFileInSharpDevelop(projectItemFileName); Document document = item.Document; Assert.AreEqual(projectItemFileName, document.FullName); } + + [Test] + public void Document_ProjectItemOpenInSharpDevelopAndIsSaved_ReturnsOpenDocumentThatIsSaved() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + OpenSavedFileInSharpDevelop(@"d:\projects\MyProject\program.cs"); + + Document document = item.Document; + + Assert.IsTrue(document.Saved); + } + + [Test] + public void Document_ProjectItemOpenInSharpDevelopAndIsUnsaved_ReturnsOpenDocumentThatIsNotSaved() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + OpenUnsavedFileInSharpDevelop(@"d:\projects\MyProject\program.cs"); + + Document document = item.Document; + + Assert.IsFalse(document.Saved); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs index 1ff7a6430c..13dd5ef64a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs @@ -126,16 +126,19 @@ namespace PackageManagement.Tests.Helpers return CompilationUnitToReturnFromGetCompilationUnit; } - public bool IsOpen(string fileName) - { - return openViews.ContainsKey(fileName); - } - Dictionary openViews = new Dictionary(); public void AddOpenView(IViewContent view, string fileName) { openViews.Add(fileName, view); } + + public IViewContent GetOpenFile(string fileName) + { + if (openViews.ContainsKey(fileName)) { + return openViews[fileName]; + } + return null; + } } } From 61cccdf063baa327e1f1efec93835e1ff8a657e9 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 20:19:23 +0100 Subject: [PATCH 27/53] Implement EnvDTE.ProjectItem.Open() The T4MVC template opens itself into the IDE if it is not already open. --- .../PackageManagement/Project/Src/EnvDTE/Project.cs | 5 +++++ .../Project/Src/EnvDTE/ProjectItem.cs | 3 ++- .../Test/Src/EnvDTE/ProjectItemTests.cs | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index 5b2ae299cb..8bfbe644da 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -296,5 +296,10 @@ namespace ICSharpCode.PackageManagement.EnvDTE { return fileService.GetOpenFile(fileName); } + + internal void OpenFile(string fileName) + { + fileService.OpenFile(fileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index c06af27178..3bb525370a 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -190,7 +190,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE public Window Open(string viewKind) { - throw new NotImplementedException(); + ContainingProject.OpenFile(FileName); + return null; } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index d0251dc2cf..784cd96f11 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -305,5 +305,18 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsFalse(document.Saved); } + + [Test] + public void Open_ViewKindIsCode_OpensFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + + Window window = item.Open(Constants.vsViewKindCode); + + Assert.AreEqual(@"d:\projects\MyProject\program.cs", fakeFileService.FileNamePassedToOpenFile); + } } } From d9ed0169a4b5c6cddd34e241e697479464866513 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 20:24:25 +0100 Subject: [PATCH 28/53] Make EnvDTE classes serialisable. --- .../Misc/PackageManagement/Project/Src/EnvDTE/Document.cs | 2 +- .../Project/Src/EnvDTE/EnumerableProjectItems.cs | 2 +- .../Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs | 2 +- src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs index 68ca69601d..bcff49be22 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs @@ -6,7 +6,7 @@ using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.PackageManagement.EnvDTE { - public class Document + public class Document : MarshalByRefObject { IViewContent view; diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs index 62e554ea5a..500f30c06d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs @@ -8,7 +8,7 @@ using System.Linq; namespace ICSharpCode.PackageManagement.EnvDTE { - public abstract class EnumerableProjectItems : IEnumerable + public abstract class EnumerableProjectItems : MarshalByRefObject, IEnumerable { public EnumerableProjectItems() { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs index 8c03c33a09..f0cb71267d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs @@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class FileCodeModel2 + public class FileCodeModel2 : MarshalByRefObject { Project project; FileProjectItem projectItem; diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs index c73e09bd2d..6c7f06e374 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs @@ -5,7 +5,7 @@ using System; namespace ICSharpCode.PackageManagement.EnvDTE { - public class Window + public class Window : MarshalByRefObject { public Window() { From 14d0d235df19fbc2bf5134c234c7dc8bbecb8324 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 26 Aug 2012 20:56:22 +0100 Subject: [PATCH 29/53] Fix cross appdomain serialisation exception for EnvDTE project items. Convert project items generated by yield return to a list before allowing them to be used in a different app domain. The class generated by using the yield keyword is not serialisable. --- .../Project/Src/EnvDTE/EnumerableProjectItems.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs index 500f30c06d..7bef56ffef 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs @@ -21,7 +21,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE public IEnumerator GetEnumerator() { - return GetProjectItems().GetEnumerator(); + return GetProjectItems().ToList().GetEnumerator(); } protected abstract IEnumerable GetProjectItems(); From 7b0d8e92c92785bacf1ed21db398227860963f3f Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 27 Aug 2012 10:54:48 +0100 Subject: [PATCH 30/53] Fix different EnvDTE behaviour between SharpDevelop and Visual Studio. Throw exception when unknown item requested from EnvDTE.ProjectItems.Item() instead of returning null. The T4MVC template relies on this behaviour when looking for folders that do not exist. --- .../PackageManagement/Project/Src/EnvDTE/ProjectItems.cs | 2 +- .../Test/Src/EnvDTE/ProjectItemsTests.cs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs index e1b4d3cf1e..a96d3dca8c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs @@ -88,7 +88,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE return item; } } - return null; + throw new ArgumentException("Unable to find item: " + name, "name"); } internal virtual ProjectItem Item(int index) diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs index 9fec6053a6..bbf272916a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs @@ -831,5 +831,14 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("AccountController.cs", projectItem.Name); } + + [Test] + public void Item_UnknownProjectItemName_ThrowsException() + { + CreateProjectItems(); + msbuildProject.AddFile("Program.cs"); + + Assert.Throws(() => projectItems.Item("unknown.cs")); + } } } From 31560dd552d99d661c9869007326073ca7168c16 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 27 Aug 2012 14:48:44 +0100 Subject: [PATCH 31/53] Add dependent files as child EnvDTE.ProjectItems. Fixes the T4MVC template from adding duplicate files to the project since it failed to find the dependent files under T4MVC.tt. --- .../Project/PackageManagement.csproj | 2 + .../Src/EnvDTE/FileProjectItemExtensions.cs | 21 ++++++++ .../Project/Src/EnvDTE/FileProjectItems.cs | 50 +++++++++++++++++++ .../Project/Src/EnvDTE/ProjectItem.cs | 14 ++++-- .../Project/Src/EnvDTE/ProjectItems.cs | 25 +++++----- .../Src/EnvDTE/ProjectItemsInsideProject.cs | 2 +- .../Test/Src/EnvDTE/ProjectItemTests.cs | 41 +++++++++++++++ .../Test/Src/Helpers/TestableProject.cs | 9 +++- 8 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index 0bf85fb523..6bd8198df0 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -125,6 +125,8 @@ + + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs new file mode 100644 index 0000000000..a685092279 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs @@ -0,0 +1,21 @@ +// 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.Project; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class FileProjectItemExtensions + { + public static bool IsDependentUponAnotherFile(this FileProjectItem projectItem) + { + return !String.IsNullOrEmpty(projectItem.DependentUpon); + } + + public static bool IsDependentUpon(this FileProjectItem projectItem, FileProjectItem otherProjectItem) + { + return projectItem.DependentUpon == otherProjectItem.Include; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs new file mode 100644 index 0000000000..5900365428 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs @@ -0,0 +1,50 @@ +// 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 System.Collections.Generic; +using System.IO; +using System.Linq; +using ICSharpCode.SharpDevelop.Gui; +using SD = ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + /// + /// A file can have child project items if it has files that depend upon it. + /// For example, winform designer files (MainForm.Designer.cs) + /// + public class FileProjectItems : ProjectItems + { + ProjectItem projectItem; + + public FileProjectItems(ProjectItem projectItem) + : base(projectItem.ContainingProject, projectItem, new PackageManagementFileService()) + { + this.projectItem = projectItem; + } + + protected override IEnumerable GetProjectItems() + { + return GetChildDependentProjectItems().ToList(); + } + + IEnumerable GetChildDependentProjectItems() + { + foreach (SD.FileProjectItem fileProjectItem in GetFileProjectItems()) { + if (fileProjectItem.IsDependentUpon(projectItem.MSBuildProjectItem)) { + yield return new ProjectItem(Project, fileProjectItem); + } + } + } + + IEnumerable GetFileProjectItems() + { + return Project + .MSBuildProject + .Items + .Where(item => item is SD.FileProjectItem) + .Select(item => (SD.FileProjectItem)item); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index 3bb525370a..8f6e5ebad5 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -25,11 +25,19 @@ namespace ICSharpCode.PackageManagement.EnvDTE { this.projectItem = projectItem; this.ContainingProject = project; - this.ProjectItems = new DirectoryProjectItems(this); + this.ProjectItems = CreateProjectItems(projectItem); CreateProperties(); Kind = GetKindFromFileProjectItemType(); } + ProjectItems CreateProjectItems(FileProjectItem projectItem) + { + if (projectItem.ItemType == ItemType.Folder) { + return new DirectoryProjectItems(this); + } + return new FileProjectItems(this); + } + internal ProjectItem(MSBuildBasedProject project, IClass c) : this(new Project(project), project.FindFile(c.CompilationUnit.FileName)) { @@ -175,7 +183,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE get { return projectItem.FileName; } } - public Document Document { + public virtual Document Document { get { return GetOpenDocument(); } } @@ -188,7 +196,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE return null; } - public Window Open(string viewKind) + public virtual Window Open(string viewKind) { ContainingProject.OpenFile(FileName); return null; diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs index a96d3dca8c..6117da940a 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs @@ -11,13 +11,12 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class ProjectItems : MarshalByRefObject, IEnumerable { - Project project; IPackageManagementFileService fileService; object parent; public ProjectItems(Project project, object parent, IPackageManagementFileService fileService) { - this.project = project; + this.Project = project; this.fileService = fileService; this.parent = parent; } @@ -26,6 +25,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { } + protected Project Project { get; private set; } + public virtual object Parent { get { return parent; } } @@ -34,8 +35,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { string include = GetIncludePathForFileCopy(filePath); CopyFileIntoProject(filePath, include); - project.AddFileProjectItemUsingPathRelativeToProject(include); - project.Save(); + Project.AddFileProjectItemUsingPathRelativeToProject(include); + Project.Save(); } /// @@ -68,7 +69,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE string GetFileNameInProjectFromProjectItemInclude(string projectItemInclude) { - return Path.Combine(project.MSBuildProject.Directory, projectItemInclude); + return Path.Combine(Project.MSBuildProject.Directory, projectItemInclude); } public virtual IEnumerator GetEnumerator() @@ -78,7 +79,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE protected virtual IEnumerable GetProjectItems() { - return new ProjectItemsInsideProject(project); + return new ProjectItemsInsideProject(Project); } internal virtual ProjectItem Item(string name) @@ -108,18 +109,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual ProjectItem AddFromDirectory(string directory) { - using (IProjectBrowserUpdater updater = project.CreateProjectBrowserUpdater()) { - ProjectItem directoryItem = project.AddDirectoryProjectItemUsingFullPath(directory); - project.Save(); + using (IProjectBrowserUpdater updater = Project.CreateProjectBrowserUpdater()) { + ProjectItem directoryItem = Project.AddDirectoryProjectItemUsingFullPath(directory); + Project.Save(); return directoryItem; } } public virtual ProjectItem AddFromFile(string fileName) { - using (IProjectBrowserUpdater updater = project.CreateProjectBrowserUpdater()) { - ProjectItem projectItem = project.AddFileProjectItemUsingFullPath(fileName); - project.Save(); + using (IProjectBrowserUpdater updater = Project.CreateProjectBrowserUpdater()) { + ProjectItem projectItem = Project.AddFileProjectItemUsingFullPath(fileName); + Project.Save(); fileService.ParseFile(fileName); return projectItem; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs index 456aea1a08..9288b193a1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE ProjectItem ConvertToProjectItem(SD.ProjectItem item) { var fileItem = item as FileProjectItem; - if (fileItem != null) { + if ((fileItem != null) && !fileItem.IsDependentUponAnotherFile()) { return ConvertFileToProjectItem(fileItem); } return null; diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index 784cd96f11..801266f38a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -318,5 +318,46 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(@"d:\projects\MyProject\program.cs", fakeFileService.FileNamePassedToOpenFile); } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_DependentFileNotAvailableFromProjectItems() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + + ProjectItems projectItems = project.ProjectItems; + + string[] expectedFiles = new string[] { + "MainForm.cs" + }; + ProjectItemCollectionAssert.AreEqual(expectedFiles, projectItems); + } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_DependentFileNotAvailableFromProject() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + + Assert.Throws(() => project.ProjectItems.Item("MainForm.Designer.cs")); + } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_ReturnsDependentFile() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + ProjectItem mainFormItem = project.ProjectItems.Item("MainForm.cs"); + + ProjectItems mainFormProjectItems = mainFormItem.ProjectItems; + + string[] expectedFiles = new string[] { + "MainForm.Designer.cs" + }; + ProjectItemCollectionAssert.AreEqual(expectedFiles, mainFormProjectItems); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs index 17d60fea25..5b53e4d7ce 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs @@ -68,7 +68,7 @@ namespace PackageManagement.Tests.Helpers { var fileProjectItem = new FileProjectItem(this, ItemType.Folder, include); ProjectService.AddProjectItem(this, fileProjectItem); - return fileProjectItem; + return fileProjectItem; } public override string AssemblyName { @@ -80,5 +80,12 @@ namespace PackageManagement.Tests.Helpers get { return rootNamespace; } set { rootNamespace = value; } } + + public FileProjectItem AddDependentFile(string include, string dependentUpon) + { + FileProjectItem dependentFile = AddFile(include); + dependentFile.DependentUpon = dependentUpon; + return dependentFile; + } } } From 3b15af69c17563cef522f428e93cfb42918fc13b Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Tue, 28 Aug 2012 20:59:33 +0100 Subject: [PATCH 32/53] Set DependentUpon for file added to EnvDTE file project item. The T4MVC template uses EnvDTE.ProjectItems.AddFromFile() to add its generated files as dependent files. If the project items belong to a file then the DependentUpon property is set in the MSBuild project. --- .../Project/Src/EnvDTE/FileProjectItems.cs | 19 ++- .../Project/Src/EnvDTE/Project.cs | 6 + .../Project/Src/EnvDTE/ProjectItems.cs | 10 +- .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/EnvDTE/FileProjectItemsTests.cs | 108 ++++++++++++++++++ .../Test/Src/EnvDTE/ProjectItemsTests.cs | 23 +++- 6 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs index 5900365428..523a352117 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs @@ -17,11 +17,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE public class FileProjectItems : ProjectItems { ProjectItem projectItem; + IPackageManagementFileService fileService; public FileProjectItems(ProjectItem projectItem) - : base(projectItem.ContainingProject, projectItem, new PackageManagementFileService()) + : this(projectItem, new PackageManagementFileService()) + { + } + + public FileProjectItems(ProjectItem projectItem, IPackageManagementFileService fileService) + : base(projectItem.ContainingProject, projectItem, fileService) { this.projectItem = projectItem; + this.fileService = fileService; } protected override IEnumerable GetProjectItems() @@ -46,5 +53,15 @@ namespace ICSharpCode.PackageManagement.EnvDTE .Where(item => item is SD.FileProjectItem) .Select(item => (SD.FileProjectItem)item); } + + protected override ProjectItem AddFileProjectItemToProject(string fileName) + { + return AddFileProjectItemWithDependent(fileName); + } + + ProjectItem AddFileProjectItemWithDependent(string fileName) + { + return Project.AddFileProjectItemWithDependentUsingFullPath(fileName, projectItem.Name); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index 8bfbe644da..17a71d99b3 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -157,9 +157,15 @@ namespace ICSharpCode.PackageManagement.EnvDTE } internal ProjectItem AddFileProjectItemUsingFullPath(string path) + { + return AddFileProjectItemWithDependentUsingFullPath(path, null); + } + + internal ProjectItem AddFileProjectItemWithDependentUsingFullPath(string path, string dependentUpon) { FileProjectItem fileProjectItem = CreateFileProjectItemUsingFullPath(path); fileProjectItem.FileName = path; + fileProjectItem.DependentUpon = dependentUpon; AddProjectItemToMSBuildProject(fileProjectItem); return new ProjectItem(this, fileProjectItem); } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs index 6117da940a..5b694bc970 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs @@ -119,13 +119,21 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual ProjectItem AddFromFile(string fileName) { using (IProjectBrowserUpdater updater = Project.CreateProjectBrowserUpdater()) { - ProjectItem projectItem = Project.AddFileProjectItemUsingFullPath(fileName); + ProjectItem projectItem = AddFileProjectItemToProject(fileName); Project.Save(); fileService.ParseFile(fileName); return projectItem; } } + /// + /// Adds a file to the project with this ProjectItems as its parent. + /// + protected virtual ProjectItem AddFileProjectItemToProject(string fileName) + { + return Project.AddFileProjectItemUsingFullPath(fileName); + } + public virtual int Count { get { return GetProjectItems().Count(); } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index 9ea4866e47..eba8c5a39f 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -98,6 +98,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs new file mode 100644 index 0000000000..9d6dff0c76 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs @@ -0,0 +1,108 @@ +// 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 System.Collections; +using System.Collections.Generic; +using System.Linq; + +using ICSharpCode.PackageManagement; +using ICSharpCode.PackageManagement.EnvDTE; +using ICSharpCode.SharpDevelop.Project; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; +using Rhino.Mocks; +using DTE = ICSharpCode.PackageManagement.EnvDTE; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class FileProjectItemsTests + { + TestableDTEProject project; + FileProjectItems fileProjectItems; + TestableProject msbuildProject; + FakeFileService fakeFileService; + + void CreateProjectWithOneFileInProjectFolder( + string include, + string projectFileName = @"c:\projects\MyProject\MyProject.csproj") + { + project = new TestableDTEProject(); + msbuildProject = project.TestableProject; + fakeFileService = project.FakeFileService; + msbuildProject.FileName = projectFileName; + msbuildProject.AddFile(include); + } + + void CreateFileProjectItemsFromFileInProjectFolder(string include) + { + DTE.ProjectItem projectItem = project.ProjectItems.Item(include); + fileProjectItems = new DTE.FileProjectItems(projectItem, fakeFileService); + } + + IProjectBrowserUpdater CreateProjectBrowserUpdater() + { + IProjectBrowserUpdater projectBrowserUpdater = MockRepository.GenerateStub(); + project.FakeProjectService.ProjectBrowserUpdater = projectBrowserUpdater; + return projectBrowserUpdater; + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_FileIsParsed() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + string parsedFileName = fakeFileService.FileNamePassedToParseFile; + Assert.AreEqual(fileName, parsedFileName); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ReturnsProjectItemAdded() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + DTE.ProjectItem itemAdded = fileProjectItems.AddFromFile(fileName); + + string fullPath = (string)itemAdded.Properties.Item("FullPath").Value; + Assert.AreEqual("MainForm.Designer.cs", itemAdded.Name); + Assert.AreEqual(fileName, fullPath); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ProjectIsSaved() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + bool saved = msbuildProject.IsSaved; + Assert.IsTrue(saved); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ProjectBrowserUpdaterIsDisposed() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + IProjectBrowserUpdater projectBrowserUpdater = CreateProjectBrowserUpdater(); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + projectBrowserUpdater.AssertWasCalled(updater => updater.Dispose()); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs index bbf272916a..e53150ff99 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs @@ -667,7 +667,7 @@ namespace PackageManagement.Tests.EnvDTE projectBrowserUpdater.AssertWasCalled(updater => updater.Dispose()); } - + [Test] public void AddFromDirectory_EmptyDirectoryInsideProject_ProjectBrowserUpdaterIsDisposed() { @@ -840,5 +840,26 @@ namespace PackageManagement.Tests.EnvDTE Assert.Throws(() => projectItems.Item("unknown.cs")); } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_FileIsAddedAsDependentFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\myproject\myproject.csproj"; + msbuildProject.AddFile("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + msbuildProject.ItemTypeToReturnFromGetDefaultItemType = ItemType.Page; + projectItems = project.ProjectItems.Item("MainForm.cs").ProjectItems; + + projectItems.AddFromFile(fileName); + + FileProjectItem fileItem = msbuildProject.FindFile(fileName); + + Assert.AreEqual("MainForm.Designer.cs", fileItem.Include); + Assert.AreEqual(fileName, fileItem.FileName); + Assert.AreEqual(ItemType.Page, fileItem.ItemType); + Assert.AreEqual(msbuildProject, fileItem.Project); + Assert.AreEqual("MainForm.cs", fileItem.DependentUpon); + } } } From a2a0f0424020f2649ce2d0c9876704e7a9010f76 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 29 Aug 2012 21:14:48 +0100 Subject: [PATCH 33/53] Add new dependent files to project browser. Update the project browser with any dependent files added to the project by the T4MVC template when it is run. --- .../Src/EnvDTE/FileProjectItemExtensions.cs | 13 ++ .../UpdateProjectBrowserFileNodesVisitor.cs | 32 +++- .../Test/Src/ProjectBrowserUpdaterTests.cs | 154 ++++++++++++++++++ 3 files changed, 195 insertions(+), 4 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs index a685092279..ca9941192b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs @@ -2,6 +2,8 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.IO; +using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE @@ -17,5 +19,16 @@ namespace ICSharpCode.PackageManagement.EnvDTE { return projectItem.DependentUpon == otherProjectItem.Include; } + + public static bool IsDependentUponFileName(this FileProjectItem projectItem, string fileName) + { + return FileUtility.IsEqualFileName(projectItem.GetDependentUponFileName(), fileName); + } + + public static string GetDependentUponFileName(this FileProjectItem projectItem) + { + string directory = Path.GetDirectoryName(projectItem.FileName); + return Path.Combine(directory, projectItem.DependentUpon); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs b/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs index 2c67688086..12edaef7a8 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs @@ -10,6 +10,7 @@ using System.Windows.Forms; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; +using DTE = ICSharpCode.PackageManagement.EnvDTE; namespace ICSharpCode.PackageManagement { @@ -48,7 +49,9 @@ namespace ICSharpCode.PackageManagement return null; if (IsImmediateParentForNewFile(directoryNode)) { - if (IsChildFileNodeMissingForNewFile(directoryNode)) { + if (IsNewFileIsDependentUponAnotherFile()) { + base.Visit(directoryNode, data); + } else if (IsChildFileNodeMissingForNewFile(directoryNode)) { AddFileOrDirectoryNodeTo(directoryNode); } } else if (IsChildDirectoryNodeMissingForNewFile(directoryNode)) { @@ -79,6 +82,11 @@ namespace ICSharpCode.PackageManagement return FileUtility.IsBaseDirectory(DirectoryForNewFileAddedToProject, directoryNode.Directory); } + bool IsNewFileIsDependentUponAnotherFile() + { + return !String.IsNullOrEmpty(newFileAddedToProject.DependentUpon); + } + string GetDirectoryForFileAddedToProject() { return Path.GetDirectoryName(newFileAddedToProject.FileName); @@ -121,10 +129,10 @@ namespace ICSharpCode.PackageManagement AddFileNodeTo(directoryNode); } } - - void AddFileNodeTo(TreeNode node) + + void AddFileNodeTo(TreeNode node, FileNodeStatus status = FileNodeStatus.InProject) { - var fileNode = new FileNode(newFileAddedToProject.FileName, FileNodeStatus.InProject); + var fileNode = new FileNode(newFileAddedToProject.FileName, status); fileNode.InsertSorted(node); } @@ -169,5 +177,21 @@ namespace ICSharpCode.PackageManagement { return parentNode.AllNodes.OfType(); } + + public override object Visit(FileNode fileNode, object data) + { + if (IsNewFileIsDependentUponAnotherFile()) { + if (IsImmediateParentForNewFile(fileNode)) { + AddFileNodeTo(fileNode, FileNodeStatus.BehindFile); + return null; + } + } + return base.Visit(fileNode, data); + } + + bool IsImmediateParentForNewFile(FileNode fileNode) + { + return DTE.FileProjectItemExtensions.IsDependentUponFileName(newFileAddedToProject, fileNode.FileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs index 3341a49b7a..d56d4dac73 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs @@ -131,6 +131,15 @@ namespace PackageManagement.Tests AddProjectItemToProject(fileProjectItem); } + void AddDependentFileToProject(string fileName, string dependentUpon) + { + var fileProjectItem = new FileProjectItem(project, ItemType.Compile) { + FileName = fileName, + DependentUpon = dependentUpon + }; + AddProjectItemToProject(fileProjectItem); + } + void AddReferenceToProject(string name) { var reference = new ReferenceProjectItem(project, name); @@ -585,5 +594,150 @@ namespace PackageManagement.Tests AssertChildFileNodesCountAreEqual(1, subfolderNode); } + + [Test] + public void Constructor_NewDependentFileAddedWhenParentFileHasNoChildren_DependentFileAddedToParentFile() + { + string projectFileName = @"d:\projects\MyProject\MyProject.csproj"; + string fileName = @"d:\projects\MyProject\MainForm.cs"; + CreateProjectNodeWithOneFileInRootDirectoryExpanded(projectFileName, fileName); + string newFileName = @"d:\projects\MyProject\MainForm.Designer.cs"; + + AddDependentFileToProject(newFileName, "MainForm.cs"); + + FileNode mainFormFileNode = GetFirstFileChildNode(projectNode); + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(newFileName, mainFormDesignerFileNode.FileName); + Assert.AreEqual(FileNodeStatus.BehindFile, mainFormDesignerFileNode.FileNodeStatus); + } + + [Test] + public void Constructor_NewDependentFileAddedWhenParentFileHasNoChildren_FileNotAddedToSameDirectoryAsParentFile() + { + string projectFileName = @"d:\projects\MyProject\MyProject.csproj"; + string fileName = @"d:\projects\MyProject\MainForm.cs"; + CreateProjectNodeWithOneFileInRootDirectoryExpanded(projectFileName, fileName); + string newFileName = @"d:\projects\MyProject\MainForm.Designer.cs"; + + AddDependentFileToProject(newFileName, "MainForm.cs"); + + // Should be only two project child nodes. + // References + MainForm.cs + Assert.AreEqual(2, projectNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasFileInProjectAndInSubdirectoryAndNewFileAddedInSubdirectory_NewFileNotAddedAsChildToExistingFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddFileToProject(@"d:\projects\MyProject\src\c.cs"); + + FileNode firstFileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, firstFileNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasThreeFilesAndDependentFileAddedToSecondFile_DependentFileAddedToSecondFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\A.cs", + @"d:\projects\MyProject\MainForm.cs", + @"d:\projects\MyProject\Z.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MainForm.cs"); + + FileNode mainFormFileNode = GetFirstChildNode(projectNode, n => n.Text == "MainForm.cs") as FileNode; + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(@"d:\projects\MyProject\MainForm.Designer.cs", mainFormDesignerFileNode.FileName); + } + + [Test] + public void Constructor_ProjectHasThreeFilesAndDependentFileAddedToSecondFile_DependentFileNotAddedToFirst() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\A.cs", + @"d:\projects\MyProject\MainForm.cs", + @"d:\projects\MyProject\Z.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MainForm.cs"); + + FileNode fileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, fileNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasOneFileAndDependentFileAddedWithDifferentCaseToParentFile_DependentFileAddedToParentFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\MainForm.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MAINFORM.CS"); + + FileNode mainFormFileNode = GetFirstFileChildNode(projectNode); + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(@"d:\projects\MyProject\MainForm.Designer.cs", mainFormDesignerFileNode.FileName); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFolders_DependentFileNotAddedToFileInDifferentDirectoryWithSameDependentName() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode firstFileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, firstFileNode.Nodes.Count); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFolders_DependentFileAddedToFileInSameDirectory() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode fileNode = GetFirstFileChildNode(srcDirectoryNode); + FileNode childNode = GetFirstFileChildNode(fileNode); + Assert.AreEqual(@"d:\projects\MyProject\src\c.cs", childNode.FileName); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFoldersAndFolderCasingDifferent_DependentFileAddedToFileInSameDirectory() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MYPROJECT\SRC\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode fileNode = GetFirstFileChildNode(srcDirectoryNode); + FileNode childNode = GetFirstFileChildNode(fileNode); + Assert.AreEqual(@"d:\projects\MyProject\src\c.cs", childNode.FileName); + } } } From debe1eae9938c7f3aa00fa0f5316b26265dc343f Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 1 Sep 2012 12:18:55 +0100 Subject: [PATCH 34/53] Fix incorrect namespace returned for EnvDTE.CodeType. The last part of the namespace was being returned by CodeNamespace.Name for a CodeType instead of the fully qualified name. --- .../Project/Src/EnvDTE/CodeType.cs | 2 +- .../Test/Src/EnvDTE/CodeClass2Tests.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs index eb7838dfc5..25b9df8a8b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs @@ -67,7 +67,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual CodeNamespace Namespace { - get { return new CodeNamespace(ProjectContent, Class.Namespace); } + get { return new FileCodeModelCodeNamespace(ProjectContent, Class.Namespace); } } public virtual ProjectItem ProjectItem { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index a9553b652a..bf558de996 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -269,6 +269,19 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("MyNamespace.Test", codeNamespace.FullName); } + [Test] + public void Namespace_PublicClassAndNamespaceNameChecked_ReturnsFullyQualifiedClassNamespace() + { + CreateProjectContent(); + helper.CreatePublicClass("MyNamespace.Test.MyClass"); + helper.AddClassNamespace("MyNamespace.Test"); + CreateClass(); + + CodeNamespace codeNamespace = codeClass.Namespace; + + Assert.AreEqual("MyNamespace.Test", codeNamespace.Name); + } + [Test] public void PartialClasses_ClassIsNotPartial_ReturnsClass() { From 12fe1bbc731bdb443fe53128a71a935a92b3bcf1 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 1 Sep 2012 13:13:06 +0100 Subject: [PATCH 35/53] Fix T4MVC template not generating method parameters. Now using CodeParameter2 instead of CodeParameter when returning parameters from CodeFunction.Parameters --- .../PackageManagement/Project/Src/EnvDTE/CodeParameters.cs | 2 +- .../PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs | 4 ++-- .../Test/Src/Helpers/CodeElementsExtensions.cs | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs index 97d7de2a22..057f55da17 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs @@ -26,7 +26,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE void AddParameters(IParameter parameter) { - AddCodeElement(new CodeParameter(projectContent, parameter)); + AddCodeElement(new CodeParameter2(projectContent, parameter)); } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index e8a36cf19a..215e7827c1 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -202,12 +202,12 @@ namespace PackageManagement.Tests.EnvDTE } [Test] - public void Parameters_MethodHasOneParameter_ReturnsOneCodeParameter() + public void Parameters_MethodHasOneParameter_ReturnsOneCodeParameter2() { AddParameterToMethod("test"); CreatePublicFunction("MyClass.MyMethod"); - CodeParameter parameter = codeFunction.Parameters.FirstCodeParameterOrDefault(); + CodeParameter2 parameter = codeFunction.Parameters.FirstCodeParameter2OrDefault(); Assert.AreEqual("test", parameter.Name); } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs index ca0b2ca1bc..a7d0eec627 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs @@ -79,6 +79,11 @@ namespace PackageManagement.Tests.Helpers return codeElements.FirstOrDefault() as CodeParameter; } + public static CodeParameter2 FirstCodeParameter2OrDefault(this CodeElements codeElements) + { + return codeElements.FirstOrDefault() as CodeParameter2; + } + public static CodeImport FirstCodeImportOrDefault(this CodeElements codeElements) { return codeElements.FirstOrDefault() as CodeImport; From d7b7ee52476eb4d4ab02516111f9a605634ea043 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 2 Sep 2012 11:32:57 +0100 Subject: [PATCH 36/53] 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. --- .../Project/PackageManagement.csproj | 2 + .../Project/Src/ClassKindUpdater.cs | 63 ++++++++ .../Project/Src/EnvDTE/CodeClass2.cs | 18 ++- .../Project/Src/IClassKindUpdater.cs | 12 ++ .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/ClassKindUpdaterTests.cs | 151 ++++++++++++++++++ .../Test/Src/EnvDTE/CodeClass2Tests.cs | 25 ++- .../Test/Src/Helpers/ClassHelper.cs | 10 ++ 8 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index 6bd8198df0..ff3c471fd3 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -74,6 +74,7 @@ + @@ -152,6 +153,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs new file mode 100644 index 0000000000..003690bf3a --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs @@ -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"; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index dbca938a8f..db0a41464c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -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 } return vsCMClassKind.vsCMClassKindMainClass; } - set { throw new NotImplementedException(); } + set { + if (value == vsCMClassKind.vsCMClassKindPartialClass) { + classKindUpdater.MakeClassPartial(); + } else { + throw new NotImplementedException(); + } + } } public bool IsAbstract { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs new file mode 100644 index 0000000000..85abf2fca7 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs @@ -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(); + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index eba8c5a39f..1c5b6579af 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -76,6 +76,7 @@ Properties\GlobalAssemblyInfo.cs + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs new file mode 100644 index 0000000000..3490cbf352 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.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 ClassKindUpdaterTests + { + ClassKindUpdater updater; + ClassHelper classHelper; + IRefactoringDocument document; + IDocumentLoader documentLoader; + + [SetUp] + public void Init() + { + classHelper = new ClassHelper(); + document = MockRepository.GenerateStub(); + documentLoader = MockRepository.GenerateStub(); + } + + 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(); + 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(() => updater.MakeClassPartial()); + } + + [Test] + public void MakeClassPartial_NoClassKeywordButClassNameIncludesClassKeyword_ExceptionIsThrown() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\MyClass.cs"); + SetClassDeclarationLine(1, "public MyClass"); + + Assert.Throws(() => 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 ")); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index bf558de996..90056df6c2 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -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 { CodeClass2 codeClass; ClassHelper helper; + IClassKindUpdater classKindUpdater; void CreateProjectContent() { @@ -42,7 +44,8 @@ namespace PackageManagement.Tests.EnvDTE void CreateClass() { - codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class); + classKindUpdater = MockRepository.GenerateStub(); + codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class, classKindUpdater); } void AddInterfaceToProjectContent(string fullName) @@ -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(() => codeClass.ClassKind = vsCMClassKind.vsCMClassKindMainClass); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index ba169b6806..04ff3afe03 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -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); + } } } From db2f9dbb065d7f0cb1865152bc33ef99ce454550 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 2 Sep 2012 14:42:52 +0100 Subject: [PATCH 37/53] 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. --- .../Project/PackageManagement.csproj | 2 + .../Project/Src/ClassKindUpdater.cs | 3 + .../Project/Src/EnvDTE/CodeFunction.cs | 12 +- .../Project/Src/IVirtualMethodUpdater.cs | 15 ++ .../Project/Src/VirtualMethodUpdater.cs | 67 ++++++++ .../Test/PackageManagement.Tests.csproj | 1 + .../Test/Src/ClassKindUpdaterTests.cs | 14 ++ .../Test/Src/EnvDTE/CodeFunctionTests.cs | 25 ++- .../Test/Src/EnvDTE/EditPointTests.cs | 2 +- .../Test/Src/VirtualMethodUpdaterTests.cs | 151 ++++++++++++++++++ 10 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs 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 ")); + } + } +} From ec75e495d4bdaab101ba753f0136c4efed836290 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 8 Sep 2012 15:04:51 +0100 Subject: [PATCH 38/53] Support running custom tools on build. Add Custom Tools project options panel that can be used to enable running custom tools when a build is started just before the build executes. Project options panel allows enabling/disabling this feature and specifying which files will have their custom tools run pre-build. Configuration is stored in IProject.ProjectSpecificProperties. --- .../Project/ICSharpCode.SharpDevelop.addin | 3 + .../Project/ICSharpCode.SharpDevelop.csproj | 9 + .../ProjectCustomToolOptionsPanel.xaml | 33 +++ .../ProjectCustomToolOptionsPanel.xaml.cs | 107 +++++++ .../BeforeBuildCustomToolFileNameFilter.cs | 36 +++ .../BeforeBuildCustomToolProjectItems.cs | 51 ++++ .../Project/BeforeBuildCustomToolRunner.cs | 30 ++ .../Base/Project/Src/Project/CustomTool.cs | 3 + .../Src/Project/ProjectCustomToolOptions.cs | 46 +++ .../ICSharpCode.SharpDevelop.Tests.csproj | 4 + .../BeforeBuildCustomToolProjectItemsTests.cs | 267 ++++++++++++++++++ .../Project/ProjectCustomToolOptionsTests.cs | 212 ++++++++++++++ src/Main/Base/Test/Utils/ProjectHelper.cs | 37 +++ 13 files changed, 838 insertions(+) create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs create mode 100644 src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs create mode 100644 src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs create mode 100644 src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs create mode 100644 src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs create mode 100644 src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs create mode 100644 src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs create mode 100644 src/Main/Base/Test/Utils/ProjectHelper.cs diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin index 7460ec489c..b3862756e3 100755 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin @@ -2273,6 +2273,9 @@ + diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index cae14dd536..807c30b6ec 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -257,6 +257,10 @@ DebugOptions.xaml Code + + ProjectCustomToolOptionsPanel.xaml + Code + @@ -350,6 +354,9 @@ + + + @@ -391,6 +398,7 @@ + @@ -905,6 +913,7 @@ + ProjectOptionPanel.cs diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml new file mode 100644 index 0000000000..ebc9aa76a9 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs new file mode 100644 index 0000000000..31ec9ebdca --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs @@ -0,0 +1,107 @@ +// 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 System.ComponentModel; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop.Gui.OptionPanels +{ + public partial class ProjectCustomToolOptionsPanel : INotifyPropertyChanged, ICanBeDirty + { + ProjectCustomToolOptions customToolsOptions; + bool runCustomToolOnBuild; + string fileNames; + bool isDirty; + + public ProjectCustomToolOptionsPanel() + { + this.DataContext = this; + InitializeComponent(); + } + + public bool RunCustomToolOnBuild { + get { return runCustomToolOnBuild; } + set { + runCustomToolOnBuild = value; + OnChanged(); + } + } + + public string FileNames { + get { return fileNames; } + set { + fileNames = value; + OnChanged(); + } + } + + void OnChanged() + { + IsDirty = OptionsHaveChanged(); + } + + bool OptionsHaveChanged() + { + return + (runCustomToolOnBuild != customToolsOptions.RunCustomToolOnBuild) || + (fileNames != customToolsOptions.FileNames); + } + + public override void LoadOptions() + { + var project = Owner as IProject; + + customToolsOptions = new ProjectCustomToolOptions(project); + RunCustomToolOnBuild = customToolsOptions.RunCustomToolOnBuild; + FileNames = customToolsOptions.FileNames; + + OnPropertyChanged(); + } + + public override bool SaveOptions() + { + if (OptionsHaveChanged()) { + customToolsOptions.RunCustomToolOnBuild = runCustomToolOnBuild; + customToolsOptions.FileNames = fileNames; + } + IsDirty = false; + return true; + } + + public event PropertyChangedEventHandler PropertyChanged; + + void OnPropertyChanged() + { + OnPropertyChanged(null); + } + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + public event EventHandler IsDirtyChanged; + + void OnIsDirtyChanged() + { + if (IsDirtyChanged != null) { + IsDirtyChanged(this, new EventArgs()); + } + } + + public bool IsDirty { + get { return isDirty; } + + private set { + if (isDirty != value) { + isDirty = value; + OnIsDirtyChanged(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs new file mode 100644 index 0000000000..f94bc9796e --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs @@ -0,0 +1,36 @@ +// 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 System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolFileNameFilter + { + List fileNames; + + public BeforeBuildCustomToolFileNameFilter(IProject project) + { + var customToolOptions = new ProjectCustomToolOptions(project); + if (customToolOptions.RunCustomToolOnBuild) { + fileNames = customToolOptions.SplitFileNames().ToList(); + } else { + fileNames = new List(); + } + } + + public bool IsMatch(string fullPath) + { + string fileNameToMatch = Path.GetFileName(fullPath); + return fileNames.Any(fileName => String.Equals(fileName, fileNameToMatch, StringComparison.OrdinalIgnoreCase)); + } + + public bool Any() + { + return fileNames.Any(); + } + } +} diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs new file mode 100644 index 0000000000..b27862a81e --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs @@ -0,0 +1,51 @@ +// 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 System.Collections.Generic; +using System.Linq; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolProjectItems + { + IBuildable buildable; + + public BeforeBuildCustomToolProjectItems(IBuildable buildable) + { + this.buildable = buildable; + } + + public IEnumerable GetProjectItems() + { + return GetProjects() + .SelectMany(p => GetConfiguredCustomToolProjectItems(p)) + .ToList(); + } + + IEnumerable GetProjects() + { + IProject project = buildable as IProject; + if (project != null) { + return new IProject[] { project }; + } + + var solution = buildable as Solution; + return solution.Projects; + } + + IEnumerable GetConfiguredCustomToolProjectItems(IProject project) + { + var fileNameFilter = new BeforeBuildCustomToolFileNameFilter(project); + if (!fileNameFilter.Any()) { + return new FileProjectItem[0]; + } + + return project + .Items + .OfType() + .Where(item => fileNameFilter.IsMatch(item.Include)); + } + } +} diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs new file mode 100644 index 0000000000..3532490e7c --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs @@ -0,0 +1,30 @@ +// 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 System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolRunner + { + public BeforeBuildCustomToolRunner() + { + ProjectService.BuildStarted += ProjectBuildStarted; + } + + void ProjectBuildStarted(object sender, BuildEventArgs e) + { + var projectItems = new BeforeBuildCustomToolProjectItems(e.Buildable); + RunCustomTool(projectItems.GetProjectItems()); + } + + void RunCustomTool(IEnumerable projectItems) + { + foreach (FileProjectItem projectItem in projectItems) { + CustomToolsService.RunCustomTool(projectItem, false); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Project/CustomTool.cs b/src/Main/Base/Project/Src/Project/CustomTool.cs index 642ef117b4..bd74c298a0 100644 --- a/src/Main/Base/Project/Src/Project/CustomTool.cs +++ b/src/Main/Base/Project/Src/Project/CustomTool.cs @@ -356,6 +356,7 @@ namespace ICSharpCode.SharpDevelop.Project static Dictionary toolDict; static List customToolList; static CustomToolRun activeToolRun; + static BeforeBuildCustomToolRunner beforeBuildCustomToolRunner; internal static void Initialize() { @@ -369,6 +370,8 @@ namespace ICSharpCode.SharpDevelop.Project initialized = true; FileUtility.FileSaved += OnFileSaved; } + + beforeBuildCustomToolRunner = new BeforeBuildCustomToolRunner(); } static void OnFileSaved(object sender, FileNameEventArgs e) diff --git a/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs new file mode 100644 index 0000000000..38d01ad02a --- /dev/null +++ b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs @@ -0,0 +1,46 @@ +// 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 System.Collections.Generic; +using System.Linq; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class ProjectCustomToolOptions + { + Properties properties; + + public ProjectCustomToolOptions(IProject project) + { + GetCustomToolProperties(project); + } + + void GetCustomToolProperties(IProject project) + { + properties = project.ProjectSpecificProperties.Get("customTool", new Properties()); + } + + public bool RunCustomToolOnBuild { + get { return properties.Get("runOnBuild", false); } + set { properties.Set("runOnBuild", value); } + } + + public string FileNames { + get { return properties.Get("fileNames", String.Empty); } + set { properties.Set("fileNames", value); } + } + + public IList SplitFileNames() + { + return + FileNames + .Replace("\r\n", ";") + .Split(';', ',') + .Select(fileName => fileName.Trim()) + .Where(fileName => !String.IsNullOrEmpty(fileName)) + .ToList(); + } + } +} diff --git a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj index 4b51d0c4f2..a13dd8902e 100644 --- a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj +++ b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj @@ -87,6 +87,8 @@ + + @@ -126,6 +128,7 @@ + @@ -183,6 +186,7 @@ ICSharpCode.Core + diff --git a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs new file mode 100644 index 0000000000..0e12ccaee9 --- /dev/null +++ b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs @@ -0,0 +1,267 @@ +// 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 System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.SharpDevelop.Tests.Utils; +using NUnit.Framework; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Project +{ + [TestFixture] + public class BeforeBuildCustomToolProjectItemsTests + { + ProjectHelper projectHelper; + BeforeBuildCustomToolProjectItems beforeBuildCustomToolProjectItems; + Solution solution; + + IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj") + { + projectHelper = new ProjectHelper(fileName); + return projectHelper.Project; + } + + void CreateSolution(params IProject[] projects) + { + IProjectChangeWatcher watcher = MockRepository.GenerateStub(); + solution = new Solution(watcher); + projects.ForEach(p => solution.Folders.Add(p)); + } + + void ConfigureCustomToolFileNamesForProject(string fileNames) + { + var customToolOptions = new ProjectCustomToolOptions(projectHelper.Project); + customToolOptions.FileNames = fileNames; + } + + void EnableCustomToolRunForProject() + { + SetCustomToolRunForProject(true); + } + + void SetCustomToolRunForProject(bool enabled) + { + var customToolOptions = new ProjectCustomToolOptions(projectHelper.Project); + customToolOptions.RunCustomToolOnBuild = enabled; + } + + void DisableCustomToolRunForProject() + { + SetCustomToolRunForProject(false); + } + + List GetProjectItems() + { + return beforeBuildCustomToolProjectItems.GetProjectItems().ToList(); + } + + void CreateBeforeBuildCustomToolProjectItems() + { + CreateBeforeBuildCustomToolProjectItems(projectHelper.Project as IBuildable); + } + + void CreateBeforeBuildCustomToolProjectItems(IBuildable buildable) + { + beforeBuildCustomToolProjectItems = new BeforeBuildCustomToolProjectItems(buildable); + } + + void CreateBeforeBuildCustomToolProjectItemsUsingSolution() + { + CreateBeforeBuildCustomToolProjectItems(solution as IBuildable); + } + + FileProjectItem AddFileToProject(string include) + { + var projectItem = new FileProjectItem(projectHelper.Project, ItemType.Compile, include); + projectHelper.AddProjectItem(projectItem); + return projectItem; + } + + [Test] + public void GetProjectItems_BuildSingleProjectNotConfiguredToRunCustomToolsOnBuild_ReturnsNoItems() + { + CreateProject(); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_OneProjectItemReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolFileNamesConfigured_NoProjectItemsReturnedWhenRunCustomToolIsDisabledForProject() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + AddFileToProject("template.tt"); + DisableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_OtherNonMatchingProjectItemsNotReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.t4"); + AddFileToProject("test.cs"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.t4"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_ProjectItemInSubdirectoryReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject(@"Model\template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_ProjectItemReturnedWhenFileNameCaseIsDifferent() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingOneProjectWithMatchingCustomToolFileName_ReturnsOneProjectItem() + { + IProject project = CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateSolution(project); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionWithNoProjects_ReturnsNoProjectItems() + { + CreateSolution(); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsWithMatchingCustomToolFileNameInSecondProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsWithMatchingCustomToolFileNameInFirstProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsBothWithFilesAndMatchingCustomToolFileNameInFirstProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + AddFileToProject("test.cs"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + } +} diff --git a/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs b/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs new file mode 100644 index 0000000000..39981dc3f2 --- /dev/null +++ b/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs @@ -0,0 +1,212 @@ +// 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 System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using NUnit.Framework; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Project +{ + [TestFixture] + public class ProjectCustomToolOptionsTests + { + IProject project; + Properties projectSpecificProperties; + ProjectCustomToolOptions projectCustomToolOptions; + Properties properties; + + void CreateProject() + { + projectSpecificProperties = new Properties(); + project = MockRepository.GenerateStub(); + project.Stub(p => p.ProjectSpecificProperties).Return(projectSpecificProperties); + } + + void CreateProjectWithExistingCustomToolProperties(string fileNames) + { + CreateProjectWithExistingCustomToolProperties(false, fileNames); + } + + void CreateProjectWithExistingCustomToolProperties(bool runOnBuild, string fileNames = "") + { + CreateProject(); + properties = new Properties(); + properties.Set("runOnBuild", runOnBuild); + properties.Set("fileNames", fileNames); + projectSpecificProperties.Set("customTool", properties); + } + + void CreateProjectCustomToolsOptions() + { + projectCustomToolOptions = new ProjectCustomToolOptions(project); + } + + [Test] + public void RunCustomToolOnBuild_ProjectHasNoExistingProjectCustomToolProperties_ReturnsFalse() + { + CreateProject(); + CreateProjectCustomToolsOptions(); + + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + + Assert.IsFalse(run); + } + + [Test] + public void FileNames_ProjectHasNoExistingProjectCustomToolProperties_ReturnsEmptyString() + { + CreateProject(); + CreateProjectCustomToolsOptions(); + + string fileNames = projectCustomToolOptions.FileNames; + + Assert.AreEqual(String.Empty, fileNames); + } + + [Test] + public void RunCustomToolOnBuild_ProjectPropertyRunCustomToolOnBuildIsTrue_ReturnsTrue() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: true); + CreateProjectCustomToolsOptions(); + + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + + Assert.IsTrue(run); + } + + [Test] + public void FileNames_ProjectPropertyFileNamesIsNotEmptyString_ReturnsFileName() + { + CreateProjectWithExistingCustomToolProperties(fileNames: "T4MVC.tt"); + CreateProjectCustomToolsOptions(); + + string fileNames = projectCustomToolOptions.FileNames; + + Assert.AreEqual("T4MVC.tt", fileNames); + } + + [Test] + public void RunCustomToolOnBuild_ChangeRunCustomToolOnBuildToTrue_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: false); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.RunCustomToolOnBuild = true; + + CreateProjectCustomToolsOptions(); + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + Assert.IsTrue(run); + } + + [Test] + public void RunCustomToolOnBuild_ChangeRunCustomToolOnBuildToFalse_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: true); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.RunCustomToolOnBuild = false; + + CreateProjectCustomToolsOptions(); + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + Assert.IsFalse(run); + } + + [Test] + public void FileNames_ChangeFileNamesFromEmptyStringToFileName_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(fileNames: String.Empty); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.FileNames = "abc.tt"; + + CreateProjectCustomToolsOptions(); + string fileNames = projectCustomToolOptions.FileNames; + Assert.AreEqual("abc.tt", fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsSemiColonSeparatedOfTwoFiles_ReturnsTwoFiles() + { + CreateProjectWithExistingCustomToolProperties("a.t4;b.t4"); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsCommaSeparatedOfTwoFiles_ReturnsTwoFiles() + { + CreateProjectWithExistingCustomToolProperties("a.t4,b.t4"); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsSemiColonSeparatedOfTwoFilesWithWhitespace_ReturnsTwoFilesWithWhitespaceRemoved() + { + CreateProjectWithExistingCustomToolProperties(" a.t4 ; b.t4 "); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsTwoFilesEachOnSeparateLine_ReturnsTwoFiles() + { + string text = + "a.t4\r\n" + + "b.t4"; + CreateProjectWithExistingCustomToolProperties(text); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsTwoFilesEachOnSeparateLineWithEmptyLineBetweenThemAndOneAtEnd_ReturnsTwoFiles() + { + string text = + "a.t4\r\n" + + "\r\n" + + "b.t4\r\n"; + CreateProjectWithExistingCustomToolProperties(text); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + } +} diff --git a/src/Main/Base/Test/Utils/ProjectHelper.cs b/src/Main/Base/Test/Utils/ProjectHelper.cs new file mode 100644 index 0000000000..459362f89c --- /dev/null +++ b/src/Main/Base/Test/Utils/ProjectHelper.cs @@ -0,0 +1,37 @@ +// 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 System.Collections.Generic; +using System.Collections.ObjectModel; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Utils +{ + public class ProjectHelper + { + public IProject Project = MockRepository.GenerateMock(); + public List ProjectItems = new List(); + public Properties ProjectSpecificProperties = new Properties(); + + public ProjectHelper(string fileName) + { + Project.Stub(p => p.FileName).Return(fileName); + + Project + .Stub(p => p.Items) + .Return(null) + .WhenCalled(mi => mi.ReturnValue = new ReadOnlyCollection(ProjectItems)); + + Project.Stub(p => p.ProjectSpecificProperties).Return(ProjectSpecificProperties); + Project.Stub(p => p.SyncRoot).Return(new Object()); + } + + public void AddProjectItem(ProjectItem projectItem) + { + ProjectItems.Add(projectItem); + } + } +} From a8f92d9e3e9e7266b7ce7cdac34b2cdb19d77345 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 9 Sep 2012 13:55:45 +0100 Subject: [PATCH 39/53] Set CustomTool for files added by NuGet. Files added (e.g. T4MVC.tt) when installing a NuGet package were not getting a default CustomTool configured. Now the CustomToolsService.GetCompatibleCustomToolNames() is used to find the first matching custom tool name for a file. --- .../FakePackageManagementProjectService.cs | 15 +++++++ .../Src/IPackageManagementProjectService.cs | 6 ++- .../Src/PackageManagementProjectService.cs | 7 ++++ .../Project/Src/SharpDevelopProjectSystem.cs | 3 +- .../Src/SharpDevelopProjectSystemTests.cs | 39 ++++++++++++++++++- 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs index ff28aa3eed..2c8390a1ab 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs @@ -99,5 +99,20 @@ namespace ICSharpCode.PackageManagement.Design { return ProjectBrowserUpdater; } + + Dictionary defaultCustomTools = new Dictionary(); + + public void AddDefaultCustomToolForFileName(string fileName, string customTool) + { + defaultCustomTools.Add(fileName, customTool); + } + + public string GetDefaultCustomToolForFileName(FileProjectItem projectItem) + { + if (defaultCustomTools.ContainsKey(projectItem.FileName)) { + return defaultCustomTools[projectItem.FileName]; + } + return String.Empty; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs index 1dfb33be21..f6b5267be1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs @@ -25,9 +25,11 @@ namespace ICSharpCode.PackageManagement void Save(Solution solution); IEnumerable GetOpenProjects(); - + IProjectContent GetProjectContent(IProject project); - + IProjectBrowserUpdater CreateProjectBrowserUpdater(); + + string GetDefaultCustomToolForFileName(FileProjectItem projectItem); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs index 9c19c31d58..b0acff35dd 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Linq; + using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Gui; @@ -109,5 +111,10 @@ namespace ICSharpCode.PackageManagement { return new ThreadSafeProjectBrowserUpdater(); } + + public string GetDefaultCustomToolForFileName(FileProjectItem projectItem) + { + return CustomToolsService.GetCompatibleCustomToolNames(projectItem).FirstOrDefault(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs index e6a387c059..cb22695907 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs @@ -212,8 +212,9 @@ namespace ICSharpCode.PackageManagement FileProjectItem CreateFileProjectItem(string path) { ItemType itemType = project.GetDefaultItemType(path); - FileProjectItem fileItem = new FileProjectItem(project, itemType); + var fileItem = new FileProjectItem(project, itemType); fileItem.FileName = path; + fileItem.CustomTool = projectService.GetDefaultCustomToolForFileName(fileItem); return fileItem; } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs index 40cf671840..ed040be096 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs @@ -38,7 +38,12 @@ namespace PackageManagement.Tests { ProjectHelper.AddFile(project, fileName); } - + + void AddDefaultCustomToolForFileName(string fileName, string customTool) + { + projectSystem.FakeProjectService.AddDefaultCustomToolForFileName(fileName, customTool); + } + [Test] public void Root_NewInstanceCreated_ReturnsProjectDirectory() { @@ -721,5 +726,37 @@ namespace PackageManagement.Tests Assert.AreEqual(expectedPath, path); } + + [Test] + public void AddFile_NewTextTemplateFileWithAssociatedDefaultCustomTool_AddsFileToProjectWithDefaultCustomTool() + { + CreateTestProject(); + CreateProjectSystem(project); + string path = @"d:\temp\abc.tt"; + AddDefaultCustomToolForFileName(path, "TextTemplatingFileGenerator"); + Stream stream = new MemoryStream(); + + projectSystem.AddFile(path, stream); + + FileProjectItem fileItem = ProjectHelper.GetFile(project, path); + string customTool = fileItem.CustomTool; + Assert.AreEqual("TextTemplatingFileGenerator", customTool); + } + + [Test] + public void AddFile_NewFileWithNoAssociatedDefaultCustomTool_AddsFileToProjectWithNoDefaultCustomTool() + { + CreateTestProject(); + CreateProjectSystem(project); + string path = @"d:\temp\abc.tt"; + AddDefaultCustomToolForFileName(path, null); + Stream stream = new MemoryStream(); + + projectSystem.AddFile(path, stream); + + FileProjectItem fileItem = ProjectHelper.GetFile(project, path); + string customTool = fileItem.CustomTool; + Assert.AreEqual(String.Empty, customTool); + } } } From 0c5fa970654f79f44aa93c2601e3b9e9603c2762 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 9 Sep 2012 20:35:57 +0100 Subject: [PATCH 40/53] Fix null reference when building a project. Pre-build custom tool runner was not handling that IProject.ProjectSpecificItems can be null for a project that has no preferences xml file already created (e.g. project created by Visual Studio and then opened in SharpDevelop). --- .../Src/Project/ProjectCustomToolOptions.cs | 6 +++++- .../BeforeBuildCustomToolProjectItemsTests.cs | 19 ++++++++++++++++++- src/Main/Base/Test/Utils/ProjectHelper.cs | 6 +++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs index 38d01ad02a..0c3e37fc3b 100644 --- a/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs +++ b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs @@ -19,7 +19,11 @@ namespace ICSharpCode.SharpDevelop.Project void GetCustomToolProperties(IProject project) { - properties = project.ProjectSpecificProperties.Get("customTool", new Properties()); + if (project.ProjectSpecificProperties != null) { + properties = project.ProjectSpecificProperties.Get("customTool", new Properties()); + } else { + properties = new Properties(); + } } public bool RunCustomToolOnBuild { diff --git a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs index 0e12ccaee9..ae5fa72800 100644 --- a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs +++ b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs @@ -23,10 +23,16 @@ namespace ICSharpCode.SharpDevelop.Tests.Project IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj") { - projectHelper = new ProjectHelper(fileName); + CreateProjectWithNoProjectSpecifiedProperties(fileName); + projectHelper.AddProjectSpecificProperties(); return projectHelper.Project; } + void CreateProjectWithNoProjectSpecifiedProperties(string fileName) + { + projectHelper = new ProjectHelper(fileName); + } + void CreateSolution(params IProject[] projects) { IProjectChangeWatcher watcher = MockRepository.GenerateStub(); @@ -263,5 +269,16 @@ namespace ICSharpCode.SharpDevelop.Tests.Project }; CollectionAssert.AreEqual(expectedProjectItems, projectItems); } + + [Test] + public void GetProjectItems_ProjectSpecificPropertiesIsNull_NoProjectItemsReturnedAndNoNullReferenceExceptionThrown() + { + CreateProjectWithNoProjectSpecifiedProperties(@"d:\MyProject\FirstProject.csproj"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } } } diff --git a/src/Main/Base/Test/Utils/ProjectHelper.cs b/src/Main/Base/Test/Utils/ProjectHelper.cs index 459362f89c..2e269ed3af 100644 --- a/src/Main/Base/Test/Utils/ProjectHelper.cs +++ b/src/Main/Base/Test/Utils/ProjectHelper.cs @@ -25,10 +25,14 @@ namespace ICSharpCode.SharpDevelop.Tests.Utils .Return(null) .WhenCalled(mi => mi.ReturnValue = new ReadOnlyCollection(ProjectItems)); - Project.Stub(p => p.ProjectSpecificProperties).Return(ProjectSpecificProperties); Project.Stub(p => p.SyncRoot).Return(new Object()); } + public void AddProjectSpecificProperties() + { + Project.Stub(p => p.ProjectSpecificProperties).Return(ProjectSpecificProperties); + } + public void AddProjectItem(ProjectItem projectItem) { ProjectItems.Add(projectItem); From e70a17822ddaec8ac9cabe39db1559858df9060c Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 9 Sep 2012 21:14:13 +0100 Subject: [PATCH 41/53] Fix project custom tool settings not being saved. If a project had no previously stored preferences then any changes made to a project's custom tool settings were lost on closing the project. --- src/Main/Base/Project/Src/Project/AbstractProject.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Main/Base/Project/Src/Project/AbstractProject.cs b/src/Main/Base/Project/Src/Project/AbstractProject.cs index f67e11ad8d..09f4d26c56 100644 --- a/src/Main/Base/Project/Src/Project/AbstractProject.cs +++ b/src/Main/Base/Project/Src/Project/AbstractProject.cs @@ -577,9 +577,17 @@ namespace ICSharpCode.SharpDevelop.Project return false; } + Properties projectSpecificProperties; + [Browsable(false)] public Properties ProjectSpecificProperties { - get; internal set; + get { + if (projectSpecificProperties == null) { + projectSpecificProperties = new Properties(); + } + return projectSpecificProperties; + } + internal set { projectSpecificProperties = value; } } protected virtual ProjectBehavior CreateDefaultBehavior() From 3e5aebd1ac23a791319ff63698890d5b4817241f Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 12 Sep 2012 07:53:02 +0200 Subject: [PATCH 42/53] Fix navigate backward/forward buttons sometimes not updating their enabled state. --- .../Project/Src/Services/NavigationService/NavigationService.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs index e41a1c43ce..7d59ac5cda 100644 --- a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs +++ b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Windows.Input; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; @@ -443,6 +444,7 @@ namespace ICSharpCode.SharpDevelop if (HistoryChanged!=null) { HistoryChanged(NavigationService.CurrentPosition, EventArgs.Empty); } + CommandManager.InvalidateRequerySuggested(); } #endregion From 11971a35afc973f8ee2ad4388b71a7831a55e787 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 12 Sep 2012 07:53:34 +0200 Subject: [PATCH 43/53] Allow values larger than 100 for ColumnRulerPosition. --- .../AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml index 3e97ec3bb9..1239bbcfd4 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml @@ -42,6 +42,8 @@ Content="{core:Localize Dialog.Options.IDEOptions.TextEditor.Markers.AtRowLabel}" /> From 09cbdfcf7a8e3ce2629701196203dd8a2fa49f95 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 12 Sep 2012 17:58:20 +0200 Subject: [PATCH 44/53] Add missing manifest to MachineSpecifications and HelpViewer addins. The addins could not be disabled due to the missing . --- .../MachineSpecifications/MachineSpecifications.addin | 4 ++++ src/AddIns/Misc/HelpViewer/HelpViewer.addin | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin b/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin index 718cd3096d..e552dd08d1 100644 --- a/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin +++ b/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin @@ -4,6 +4,10 @@ description = "Runner for Machine.Specifications unit tests for SharpDevelop" addInManagerHidden = "preinstalled"> + + + + diff --git a/src/AddIns/Misc/HelpViewer/HelpViewer.addin b/src/AddIns/Misc/HelpViewer/HelpViewer.addin index 695899bac5..bab09bb5d6 100644 --- a/src/AddIns/Misc/HelpViewer/HelpViewer.addin +++ b/src/AddIns/Misc/HelpViewer/HelpViewer.addin @@ -4,6 +4,10 @@ description = "Help Integration for SharpDevelop" addInManagerHidden = "preinstalled"> + + + + From 06f2886d1ffef9d2007a78788622b0a1a864189b Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Thu, 13 Sep 2012 20:15:29 +0100 Subject: [PATCH 45/53] Fix AspNet.Mvc tests being run with NUnit 64-bit and failing. --- src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln b/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln index 26144ff509..1aa05f4665 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln +++ b/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln @@ -44,10 +44,10 @@ Global {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|x86.ActiveCfg = Debug|x86 {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|x86.Build.0 = Release|x86 {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|x86.ActiveCfg = Release|x86 - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.Build.0 = Release|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.Build.0 = Debug|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.ActiveCfg = Debug|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.Build.0 = Release|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.ActiveCfg = Release|x86 {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|x86.Build.0 = Debug|Any CPU {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|x86.ActiveCfg = Debug|Any CPU {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.Build.0 = Debug|Any CPU From 4aef0a218927304c9a20784d587ec2db19738809 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Thu, 13 Sep 2012 21:32:16 +0100 Subject: [PATCH 46/53] Add simple dot completion for C# Razor files. Support very basic dot completion for T4MVC code inside a C# Razor file. --- .../AspNet.Mvc/Project/AspNet.Mvc.addin | 12 +++++ .../AspNet.Mvc/Project/AspNet.Mvc.csproj | 5 ++ .../RazorCSharpCompletionBinding.cs | 30 +++++++++++ .../RazorCSharpDotCompletionDataProvider.cs | 23 +++++++++ .../Completion/RazorCSharpExpressionFinder.cs | 43 ++++++++++++++++ .../Src/Completion/RazorCSharpParser.cs | 50 +++++++++++++++++++ .../Project/Src/Folding/FoldGenerator.cs | 2 +- 7 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin index 7bdb43077a..d68ee53668 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin @@ -124,4 +124,16 @@ class="ICSharpCode.AspNet.Mvc.WebProjectOptionsPanel"/> + + + + + + + + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj index 34524f74cd..1f159d0b72 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj @@ -122,6 +122,10 @@ + + + + @@ -257,6 +261,7 @@ + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs new file mode 100644 index 0000000000..4b8790a13f --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs @@ -0,0 +1,30 @@ +// 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.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpCompletionBinding : ICodeCompletionBinding + { + public RazorCSharpCompletionBinding() + { + } + + public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) + { + if (ch == '.') { + new RazorCSharpDotCompletionDataProvider().ShowCompletion(editor); + return CodeCompletionKeyPressResult.Completed; + } + return CodeCompletionKeyPressResult.None; + } + + public bool CtrlSpace(ITextEditor editor) + { + return false; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs new file mode 100644 index 0000000000..3e3c647365 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -0,0 +1,23 @@ +// 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; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpDotCompletionDataProvider : DotCodeCompletionItemProvider + { + public override ResolveResult Resolve(ITextEditor editor, ExpressionResult expressionResult) + { + ParseInformation parseInfo = ParserService.GetParseInformation(editor.FileName); + NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.CSharp); + resolver.LimitMethodExtractionUntilLine = editor.Caret.Line; + return resolver.Resolve(expressionResult, parseInfo, editor.Document.Text); + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs new file mode 100644 index 0000000000..705f4c8029 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs @@ -0,0 +1,43 @@ +// 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; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpExpressionFinder : IExpressionFinder + { + public RazorCSharpExpressionFinder() + { + } + + public ExpressionResult FindExpression(string text, int offset) + { + int position = offset - 1; + while (position > 0 && IsValidCharacter(text[position])) { + position--; + } + position++; + string expression = text.Substring(position, offset - position); + return new ExpressionResult(expression); + } + + bool IsValidCharacter(char ch) + { + return Char.IsLetterOrDigit(ch) || + (ch == '.') || + (ch == '_'); + } + + public ExpressionResult FindFullExpression(string text, int offset) + { + return ExpressionResult.Empty; + } + + public string RemoveLastPart(string expression) + { + return expression; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs new file mode 100644 index 0000000000..b1a278c26d --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs @@ -0,0 +1,50 @@ +// 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 System.IO; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpParser : IParser + { + public RazorCSharpParser() + { + } + + public string[] LexerTags { get; set; } + + public LanguageProperties Language { + get { return LanguageProperties.CSharp; } + } + + public IExpressionFinder CreateExpressionFinder(string fileName) + { + return new RazorCSharpExpressionFinder(); + } + + public bool CanParse(string fileName) + { + return Path.GetExtension(fileName).Equals(".cshtml", StringComparison.OrdinalIgnoreCase); + } + + public bool CanParse(IProject project) + { + return project.Language == "C#"; + } + + public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ITextBuffer fileContent) + { + return new DefaultCompilationUnit(projectContent); + } + + public IResolver CreateResolver() + { + return null; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs index a65867b9bb..9dcefd4b2a 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs @@ -30,8 +30,8 @@ namespace ICSharpCode.AspNet.Mvc.Folding public void Dispose() { - IsParseInformationFoldingEnabled = true; textEditor.Dispose(); + IsParseInformationFoldingEnabled = true; } public void GenerateFolds() From 98ada4ef5255cb261024ec7437f5cf7ec3c50c78 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 15 Sep 2012 12:07:31 +0100 Subject: [PATCH 47/53] Fix null reference exception when running project. BeforeBuildCustomToolProjectItems was not handling IBuildable derived classes that were not either a Project or Solution. This happens when a project is run and SharpDevelop is configured to build modified projects or build modified projects and dependent projects or when running unit tests. Now custom tools are only run when a project or solution is explicitly rebuilt or built using the Build/Rebuild from the Build menu. --- .../BeforeBuildCustomToolProjectItems.cs | 6 ++- .../BeforeBuildCustomToolProjectItemsTests.cs | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs index b27862a81e..b710b670e0 100644 --- a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs @@ -32,7 +32,11 @@ namespace ICSharpCode.SharpDevelop.Project } var solution = buildable as Solution; - return solution.Projects; + if (solution != null) { + return solution.Projects; + } + + return new IProject[0]; } IEnumerable GetConfiguredCustomToolProjectItems(IProject project) diff --git a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs index ae5fa72800..788413a747 100644 --- a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs +++ b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs @@ -21,6 +21,27 @@ namespace ICSharpCode.SharpDevelop.Tests.Project BeforeBuildCustomToolProjectItems beforeBuildCustomToolProjectItems; Solution solution; + class UnknownBuildable : IBuildable + { + public string Name { get; set; } + + public Solution ParentSolution { get; set; } + + public ICollection GetBuildDependencies(ProjectBuildOptions buildOptions) + { + return new IBuildable[0]; + } + + public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) + { + } + + public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) + { + return new ProjectBuildOptions(BuildTarget.Build); + } + } + IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj") { CreateProjectWithNoProjectSpecifiedProperties(fileName); @@ -89,6 +110,12 @@ namespace ICSharpCode.SharpDevelop.Tests.Project return projectItem; } + void CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass() + { + var unknownBuildable = new UnknownBuildable(); + CreateBeforeBuildCustomToolProjectItems(unknownBuildable); + } + [Test] public void GetProjectItems_BuildSingleProjectNotConfiguredToRunCustomToolsOnBuild_ReturnsNoItems() { @@ -280,5 +307,15 @@ namespace ICSharpCode.SharpDevelop.Tests.Project Assert.AreEqual(0, projectItems.Count); } + + [Test] + public void GetProjectItems_UnknownIBuildableDerivedClass_NullReferenceExceptionIsNotThrown() + { + CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } } } From ebbc850754f6c8475ec3ee585e529578e6eb57d5 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 16 Sep 2012 11:47:57 +0100 Subject: [PATCH 48/53] Add basic C# Razor completion for WebViewPage members. Dot completion now shows members of the WebViewPage class which is the base class of Razor view pages. --- .../RazorCSharpDotCompletionDataProvider.cs | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs index 3e3c647365..b5015ec062 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -14,10 +14,53 @@ namespace ICSharpCode.AspNet.Mvc.Completion { public override ResolveResult Resolve(ITextEditor editor, ExpressionResult expressionResult) { + NRefactoryResolver resolver = CreateResolver(editor); ParseInformation parseInfo = ParserService.GetParseInformation(editor.FileName); - NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.CSharp); - resolver.LimitMethodExtractionUntilLine = editor.Caret.Line; - return resolver.Resolve(expressionResult, parseInfo, editor.Document.Text); + ParseInformation parseInfoWithWebViewPageClass = CreateParseInformationWithWebViewPageClass(parseInfo); + expressionResult.Region = GetRegionInMiddleOfWebViewPageClass(); + return resolver.Resolve(expressionResult, parseInfoWithWebViewPageClass, editor.Document.Text); + } + + NRefactoryResolver CreateResolver(ITextEditor editor) + { + return new NRefactoryResolver(LanguageProperties.CSharp) { + LimitMethodExtractionUntilLine = editor.Caret.Line + }; + } + + ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) + { + var compilationUnit = new DefaultCompilationUnit(parseInfo.CompilationUnit.ProjectContent); + AddWebViewPageClass(compilationUnit); + return new ParseInformation(compilationUnit); + } + + void AddWebViewPageClass(DefaultCompilationUnit compilationUnit) + { + DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); + compilationUnit.Classes.Add(webViewPageClass); + } + + DefaultClass CreateWebViewPageClass(ICompilationUnit compilationUnit) + { + var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") { + Region = new DomRegion(1, 0, 3, 0) + }; + AddWebViewPageBaseClass(webViewPageClass); + return webViewPageClass; + } + + void AddWebViewPageBaseClass(DefaultClass webViewPageClass) + { + IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 0); + if (webViewPageBaseClass != null) { + webViewPageClass.BaseTypes.Add(webViewPageBaseClass.DefaultReturnType); + } + } + + DomRegion GetRegionInMiddleOfWebViewPageClass() + { + return new DomRegion(2, 0, 2, 0); } } } From e5836be58e91f120c8c0fa751b1f93ed822cbe78 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 16 Sep 2012 12:59:52 +0100 Subject: [PATCH 49/53] Add C# Razor completion for MVC helper methods. Use WebViewPage as Razor view's base class. Add default namespaces for the Razor view class so extension methods show in completion: System.Web.Mvc, System.Web.Mvc.Ajax, System.Web.Mvc.Html, System.Web.Routing The Razor view's base class and namespaces should be taken from the web.config but are currently hard coded. --- .../RazorCSharpDotCompletionDataProvider.cs | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs index b5015ec062..0ed8a6889d 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; @@ -31,10 +32,32 @@ namespace ICSharpCode.AspNet.Mvc.Completion ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) { var compilationUnit = new DefaultCompilationUnit(parseInfo.CompilationUnit.ProjectContent); + AddDefaultUsings(compilationUnit); AddWebViewPageClass(compilationUnit); return new ParseInformation(compilationUnit); } + void AddDefaultUsings(ICompilationUnit compilationUnit) + { + AddUsing("System.Web.Mvc", compilationUnit); + AddUsing("System.Web.Mvc.Ajax", compilationUnit); + AddUsing("System.Web.Mvc.Html", compilationUnit); + AddUsing("System.Web.Routing", compilationUnit); + } + + void AddUsing(string name, ICompilationUnit compilationUnit) + { + DefaultUsing defaultUsing = CreateUsing(name, compilationUnit.ProjectContent); + compilationUnit.UsingScope.Usings.Add(defaultUsing); + } + + DefaultUsing CreateUsing(string namespaceName, IProjectContent projectContent) + { + var defaultUsing = new DefaultUsing(projectContent); + defaultUsing.Usings.Add(namespaceName); + return defaultUsing; + } + void AddWebViewPageClass(DefaultCompilationUnit compilationUnit) { DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); @@ -52,12 +75,20 @@ namespace ICSharpCode.AspNet.Mvc.Completion void AddWebViewPageBaseClass(DefaultClass webViewPageClass) { - IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 0); + IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1); if (webViewPageBaseClass != null) { - webViewPageClass.BaseTypes.Add(webViewPageBaseClass.DefaultReturnType); + IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass); + webViewPageClass.BaseTypes.Add(returnType); } } + IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass) + { + var typeArguments = new List(); + typeArguments.Add(new DynamicReturnType(webViewPageBaseClass.ProjectContent)); + return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments); + } + DomRegion GetRegionInMiddleOfWebViewPageClass() { return new DomRegion(2, 0, 2, 0); From 7a742d922f7654843d1a02dec49d7106979695ff Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 16 Sep 2012 18:42:05 +0100 Subject: [PATCH 50/53] Add C# Razor completion for model. Use the @model directive to generate a strongly typed WebViewPage class. Support completion on the Model property in a view. --- .../AspNet.Mvc/Project/AspNet.Mvc.csproj | 3 + .../RazorCSharpDotCompletionDataProvider.cs | 34 +++- .../Completion/RazorCSharpModelTypeLocater.cs | 34 ++++ .../Src/Completion/RazorCSharpParser.cs | 5 +- .../RazorCSharpParserModelTypeVisitor.cs | 59 +++++++ .../Src/Completion/RazorCompilationUnit.cs | 34 ++++ .../AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj | 2 + .../Src/Completion/RazorCSharpParserTests.cs | 148 ++++++++++++++++++ 8 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj index 1f159d0b72..545ecdcfca 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj @@ -122,10 +122,13 @@ + + + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs index 0ed8a6889d..e2aba9cad3 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.AspNet.Mvc.Completion ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) { - var compilationUnit = new DefaultCompilationUnit(parseInfo.CompilationUnit.ProjectContent); + RazorCompilationUnit compilationUnit = RazorCompilationUnit.CreateFromParseInfo(parseInfo); AddDefaultUsings(compilationUnit); AddWebViewPageClass(compilationUnit); return new ParseInformation(compilationUnit); @@ -58,34 +58,52 @@ namespace ICSharpCode.AspNet.Mvc.Completion return defaultUsing; } - void AddWebViewPageClass(DefaultCompilationUnit compilationUnit) + void AddWebViewPageClass(RazorCompilationUnit compilationUnit) { DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); compilationUnit.Classes.Add(webViewPageClass); } - DefaultClass CreateWebViewPageClass(ICompilationUnit compilationUnit) + DefaultClass CreateWebViewPageClass(RazorCompilationUnit compilationUnit) { var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") { Region = new DomRegion(1, 0, 3, 0) }; - AddWebViewPageBaseClass(webViewPageClass); + IReturnType modelType = GetModelReturnType(compilationUnit); + AddWebViewPageBaseClass(webViewPageClass, modelType); return webViewPageClass; } - void AddWebViewPageBaseClass(DefaultClass webViewPageClass) + IReturnType GetModelReturnType(RazorCompilationUnit compilationUnit) + { + IClass modelType = GetClassIfTypeNameIsNotEmpty(compilationUnit.ProjectContent, compilationUnit.ModelTypeName); + if (modelType != null) { + return modelType.DefaultReturnType; + } + return new DynamicReturnType(compilationUnit.ProjectContent); + } + + IClass GetClassIfTypeNameIsNotEmpty(IProjectContent projectContent, string modelTypeName) + { + if (!String.IsNullOrEmpty(modelTypeName)) { + return projectContent.GetClass(modelTypeName, 0); + } + return null; + } + + void AddWebViewPageBaseClass(DefaultClass webViewPageClass, IReturnType modelType) { IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1); if (webViewPageBaseClass != null) { - IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass); + IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass, modelType); webViewPageClass.BaseTypes.Add(returnType); } } - IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass) + IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass, IReturnType modelType) { var typeArguments = new List(); - typeArguments.Add(new DynamicReturnType(webViewPageBaseClass.ProjectContent)); + typeArguments.Add(modelType); return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments); } diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs new file mode 100644 index 0000000000..36c72f8381 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs @@ -0,0 +1,34 @@ +// 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 System.Web.Razor; +using ICSharpCode.SharpDevelop; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpModelTypeLocater + { + public RazorCSharpModelTypeLocater(ITextBuffer textBuffer) + { + ParserResults results = ParseTemplate(textBuffer); + ModelTypeName = GetModelTypeName(results); + } + + ParserResults ParseTemplate(ITextBuffer textBuffer) + { + var host = new RazorEngineHost(new CSharpRazorCodeLanguage()); + var engine = new RazorTemplateEngine(host); + return engine.ParseTemplate(textBuffer.CreateReader()); + } + + string GetModelTypeName(ParserResults results) + { + var visitor = new RazorCSharpParserModelTypeVisitor(); + results.Document.Accept(visitor); + return visitor.ModelTypeName; + } + + public string ModelTypeName { get; private set; } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs index b1a278c26d..1d8d7645eb 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs @@ -39,7 +39,10 @@ namespace ICSharpCode.AspNet.Mvc.Completion public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ITextBuffer fileContent) { - return new DefaultCompilationUnit(projectContent); + var modelTypeLocater = new RazorCSharpModelTypeLocater(fileContent); + return new RazorCompilationUnit(projectContent) { + ModelTypeName = modelTypeLocater.ModelTypeName + }; } public IResolver CreateResolver() diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs new file mode 100644 index 0000000000..c1424045ca --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs @@ -0,0 +1,59 @@ +// 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 System.Web.Razor.Parser; +using System.Web.Razor.Parser.SyntaxTree; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpParserModelTypeVisitor : ParserVisitor + { + bool foundModelTypeName; + + public RazorCSharpParserModelTypeVisitor() + { + ModelTypeName = String.Empty; + } + + public string ModelTypeName { get; private set; } + + public override void VisitSpan(Span span) + { + Console.WriteLine("Span.Kind: " + span.Kind); + Console.WriteLine("Span.GetType(): " + span.GetType().Name); + Console.WriteLine("Span.Content: '" + span.Content + "'"); + + if (foundModelTypeName) + return; + + if (IsModelSpan(span)) { + VisitModelNameSpan(span.Next); + } + } + + bool IsModelSpan(Span span) + { + return span.Content == "model"; + } + + void VisitModelNameSpan(Span span) + { + if (span == null) + return; + + string firstLineOfMarkup = GetFirstLine(span.Content); + ModelTypeName = firstLineOfMarkup.Trim(); + foundModelTypeName = true; + } + + string GetFirstLine(string text) + { + int endOfLineIndex = text.IndexOf('\r'); + if (endOfLineIndex > 0) { + return text.Substring(0, endOfLineIndex); + } + return text; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs new file mode 100644 index 0000000000..498c929da1 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs @@ -0,0 +1,34 @@ +// 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; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCompilationUnit : DefaultCompilationUnit + { + public RazorCompilationUnit(IProjectContent projectContent) + : base(projectContent) + { + } + + public static RazorCompilationUnit CreateFromParseInfo(ParseInformation parseInformation) + { + return new RazorCompilationUnit(parseInformation.CompilationUnit.ProjectContent) { + ModelTypeName = GetModelTypeName(parseInformation.CompilationUnit) + }; + } + + static string GetModelTypeName(ICompilationUnit compilationUnit) + { + var originalRazorCompilationUnit = compilationUnit as RazorCompilationUnit; + if (originalRazorCompilationUnit != null) { + return originalRazorCompilationUnit.ModelTypeName; + } + return String.Empty; + } + + public string ModelTypeName { get; set; } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj index e4487ba0af..f0bf407d37 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj @@ -117,6 +117,7 @@ + @@ -189,6 +190,7 @@ + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs new file mode 100644 index 0000000000..0ec664c234 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs @@ -0,0 +1,148 @@ +// 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.AspNet.Mvc.Completion; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using NUnit.Framework; + +namespace AspNet.Mvc.Tests.Completion +{ + [TestFixture] + public class RazorCSharpParserTests + { + RazorCSharpParser parser; + + void CreateParser() + { + parser = new RazorCSharpParser(); + } + + ICompilationUnit Parse(string code) + { + var projectContent = new DefaultProjectContent(); + var textBuffer = new StringTextBuffer(code); + return parser.Parse(projectContent, @"d:\MyProject\Views\Index.cshtml", textBuffer); + } + + [Test] + public void Parse_ModelDirectiveWithTypeName_ModelTypeNameFound() + { + CreateParser(); + string code = "@model MvcApplication.MyModel\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelDirectiveWithTypeNameFollowedByHtmlMarkup_ModelTypeNameFound() + { + CreateParser(); + string code = + "@model MvcApplication.LogonModel\r\n" + + "

Index

\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.LogonModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_SingleLineFileWithModelDirectiveAndTypeNameButNoNewLineAtEnd_ModelTypeNameFound() + { + CreateParser(); + string code = "@model MvcApplication.MyModel"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelTypeDirectiveWithTypeNameFollowedByRazorBlock_ModelTypeNameFound() + { + CreateParser(); + + string code = + "@model IEnumerable\r\n" + + "\r\n" + + "@{\r\n" + + " ViewBag.Title = \"Title1\";\r\n" + + "}\r\n" + + "\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("IEnumerable", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_UsingDirective_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@using System.Xml\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_HelperDirective_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@helper MyHelper\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_HtmlMarkupOnly_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "

heading

\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelDirectiveOnly_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@model"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelStringInsideParagraphTags_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "

model

"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelStringOnlyWithoutRazorTransition_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "model"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + } +} From 83e9ad2722feb17c94e1969010aaad299e292908 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sun, 16 Sep 2012 21:35:04 +0100 Subject: [PATCH 51/53] Enable method insight for C# Razor views. --- .../AspNet.Mvc/Project/AspNet.Mvc.csproj | 1 + .../RazorCSharpCompletionBinding.cs | 11 +- .../RazorCSharpDotCompletionDataProvider.cs | 98 ---------------- .../Src/Completion/RazorCSharpParser.cs | 2 +- .../Src/Completion/RazorCSharpResolver.cs | 105 ++++++++++++++++++ 5 files changed, 111 insertions(+), 106 deletions(-) create mode 100644 src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj index 545ecdcfca..d16b77692d 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj @@ -129,6 +129,7 @@ + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs index 4b8790a13f..d0a5ada85b 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs @@ -7,24 +7,21 @@ using ICSharpCode.SharpDevelop.Editor.CodeCompletion; namespace ICSharpCode.AspNet.Mvc.Completion { - public class RazorCSharpCompletionBinding : ICodeCompletionBinding + public class RazorCSharpCompletionBinding : DefaultCodeCompletionBinding { public RazorCSharpCompletionBinding() { } - public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) + public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) { if (ch == '.') { new RazorCSharpDotCompletionDataProvider().ShowCompletion(editor); return CodeCompletionKeyPressResult.Completed; + } else if (ch == '(') { + return base.HandleKeyPress(editor, ch); } return CodeCompletionKeyPressResult.None; } - - public bool CtrlSpace(ITextEditor editor) - { - return false; - } } } diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs index e2aba9cad3..7a033d314f 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -13,103 +13,5 @@ namespace ICSharpCode.AspNet.Mvc.Completion { public class RazorCSharpDotCompletionDataProvider : DotCodeCompletionItemProvider { - public override ResolveResult Resolve(ITextEditor editor, ExpressionResult expressionResult) - { - NRefactoryResolver resolver = CreateResolver(editor); - ParseInformation parseInfo = ParserService.GetParseInformation(editor.FileName); - ParseInformation parseInfoWithWebViewPageClass = CreateParseInformationWithWebViewPageClass(parseInfo); - expressionResult.Region = GetRegionInMiddleOfWebViewPageClass(); - return resolver.Resolve(expressionResult, parseInfoWithWebViewPageClass, editor.Document.Text); - } - - NRefactoryResolver CreateResolver(ITextEditor editor) - { - return new NRefactoryResolver(LanguageProperties.CSharp) { - LimitMethodExtractionUntilLine = editor.Caret.Line - }; - } - - ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) - { - RazorCompilationUnit compilationUnit = RazorCompilationUnit.CreateFromParseInfo(parseInfo); - AddDefaultUsings(compilationUnit); - AddWebViewPageClass(compilationUnit); - return new ParseInformation(compilationUnit); - } - - void AddDefaultUsings(ICompilationUnit compilationUnit) - { - AddUsing("System.Web.Mvc", compilationUnit); - AddUsing("System.Web.Mvc.Ajax", compilationUnit); - AddUsing("System.Web.Mvc.Html", compilationUnit); - AddUsing("System.Web.Routing", compilationUnit); - } - - void AddUsing(string name, ICompilationUnit compilationUnit) - { - DefaultUsing defaultUsing = CreateUsing(name, compilationUnit.ProjectContent); - compilationUnit.UsingScope.Usings.Add(defaultUsing); - } - - DefaultUsing CreateUsing(string namespaceName, IProjectContent projectContent) - { - var defaultUsing = new DefaultUsing(projectContent); - defaultUsing.Usings.Add(namespaceName); - return defaultUsing; - } - - void AddWebViewPageClass(RazorCompilationUnit compilationUnit) - { - DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); - compilationUnit.Classes.Add(webViewPageClass); - } - - DefaultClass CreateWebViewPageClass(RazorCompilationUnit compilationUnit) - { - var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") { - Region = new DomRegion(1, 0, 3, 0) - }; - IReturnType modelType = GetModelReturnType(compilationUnit); - AddWebViewPageBaseClass(webViewPageClass, modelType); - return webViewPageClass; - } - - IReturnType GetModelReturnType(RazorCompilationUnit compilationUnit) - { - IClass modelType = GetClassIfTypeNameIsNotEmpty(compilationUnit.ProjectContent, compilationUnit.ModelTypeName); - if (modelType != null) { - return modelType.DefaultReturnType; - } - return new DynamicReturnType(compilationUnit.ProjectContent); - } - - IClass GetClassIfTypeNameIsNotEmpty(IProjectContent projectContent, string modelTypeName) - { - if (!String.IsNullOrEmpty(modelTypeName)) { - return projectContent.GetClass(modelTypeName, 0); - } - return null; - } - - void AddWebViewPageBaseClass(DefaultClass webViewPageClass, IReturnType modelType) - { - IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1); - if (webViewPageBaseClass != null) { - IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass, modelType); - webViewPageClass.BaseTypes.Add(returnType); - } - } - - IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass, IReturnType modelType) - { - var typeArguments = new List(); - typeArguments.Add(modelType); - return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments); - } - - DomRegion GetRegionInMiddleOfWebViewPageClass() - { - return new DomRegion(2, 0, 2, 0); - } } } diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs index 1d8d7645eb..7bd506f5c4 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs @@ -47,7 +47,7 @@ namespace ICSharpCode.AspNet.Mvc.Completion public IResolver CreateResolver() { - return null; + return new RazorCSharpResolver(); } } } diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs new file mode 100644 index 0000000000..b4641316c6 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs @@ -0,0 +1,105 @@ +// 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 System.Collections.Generic; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpResolver : IResolver + { + NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.CSharp); + + public ResolveResult Resolve(ExpressionResult expressionResult, ParseInformation parseInfo, string fileContent) + { + ParseInformation parseInfoWithWebViewPageClass = CreateParseInformationWithWebViewPageClass(parseInfo); + expressionResult.Region = GetRegionInMiddleOfWebViewPageClass(); + return resolver.Resolve(expressionResult, parseInfoWithWebViewPageClass, fileContent); + } + + ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) + { + RazorCompilationUnit compilationUnit = RazorCompilationUnit.CreateFromParseInfo(parseInfo); + AddDefaultUsings(compilationUnit); + AddWebViewPageClass(compilationUnit); + return new ParseInformation(compilationUnit); + } + + void AddDefaultUsings(ICompilationUnit compilationUnit) + { + AddUsing("System.Web.Mvc", compilationUnit); + AddUsing("System.Web.Mvc.Ajax", compilationUnit); + AddUsing("System.Web.Mvc.Html", compilationUnit); + AddUsing("System.Web.Routing", compilationUnit); + } + + void AddUsing(string name, ICompilationUnit compilationUnit) + { + DefaultUsing defaultUsing = CreateUsing(name, compilationUnit.ProjectContent); + compilationUnit.UsingScope.Usings.Add(defaultUsing); + } + + DefaultUsing CreateUsing(string namespaceName, IProjectContent projectContent) + { + var defaultUsing = new DefaultUsing(projectContent); + defaultUsing.Usings.Add(namespaceName); + return defaultUsing; + } + + void AddWebViewPageClass(RazorCompilationUnit compilationUnit) + { + DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); + compilationUnit.Classes.Add(webViewPageClass); + } + + DefaultClass CreateWebViewPageClass(RazorCompilationUnit compilationUnit) + { + var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") { + Region = new DomRegion(1, 0, 3, 0) + }; + IReturnType modelType = GetModelReturnType(compilationUnit); + AddWebViewPageBaseClass(webViewPageClass, modelType); + return webViewPageClass; + } + + IReturnType GetModelReturnType(RazorCompilationUnit compilationUnit) + { + IClass modelType = GetClassIfTypeNameIsNotEmpty(compilationUnit.ProjectContent, compilationUnit.ModelTypeName); + if (modelType != null) { + return modelType.DefaultReturnType; + } + return new DynamicReturnType(compilationUnit.ProjectContent); + } + + IClass GetClassIfTypeNameIsNotEmpty(IProjectContent projectContent, string modelTypeName) + { + if (!String.IsNullOrEmpty(modelTypeName)) { + return projectContent.GetClass(modelTypeName, 0); + } + return null; + } + + void AddWebViewPageBaseClass(DefaultClass webViewPageClass, IReturnType modelType) + { + IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1); + if (webViewPageBaseClass != null) { + IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass, modelType); + webViewPageClass.BaseTypes.Add(returnType); + } + } + + IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass, IReturnType modelType) + { + var typeArguments = new List(); + typeArguments.Add(modelType); + return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments); + } + + DomRegion GetRegionInMiddleOfWebViewPageClass() + { + return new DomRegion(2, 0, 2, 0); + } + } +} From 18ba138e8aeb139fc656627fed2fd54b3fa06c45 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 18 Sep 2012 15:10:04 +0200 Subject: [PATCH 52/53] Floating windows: Avoid updating ActiveContent/ActiveDocument in the middle of a layout restore. This fixes "System.InvalidOperationException: Unable to set active document" in AvalonDock.DockingManager.CoerceActiveDocumentValue. (or at least one cause of that exception) --- src/Libraries/AvalonDock/AvalonDock/DockingManager.cs | 2 +- src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs b/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs index b65cdc147d..4af71ae898 100644 --- a/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs +++ b/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs @@ -3752,7 +3752,7 @@ namespace AvalonDock /// /// True while is restoring a layout /// - protected bool RestoringLayout { get; private set; } + protected internal bool RestoringLayout { get; private set; } /// /// Internal main restore layout method diff --git a/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs b/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs index d43ad44dcb..37acfae08c 100644 --- a/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs +++ b/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs @@ -340,7 +340,7 @@ namespace AvalonDock protected override void OnDeactivated(EventArgs e) { - if (Manager != null && lastActiveContent != null) + if (Manager != null && !Manager.RestoringLayout && lastActiveContent != null) { Manager.ActiveContent = lastActiveContent; } From 6d39f5965b225fbbb833f76d2ebac73237864dbc Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 18 Sep 2012 16:54:59 +0200 Subject: [PATCH 53/53] [AvalonDock] Fix "InvalidOperationException: This Visual is not connected to a PresentationSource" when closing a view content by middle-clicking while holding the left mouse button. --- src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs b/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs index 1259179fe0..501ac136bd 100644 --- a/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs +++ b/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs @@ -337,7 +337,9 @@ namespace AvalonDock protected virtual void OnDragMouseLeave(object sender, MouseEventArgs e) { - if (!e.Handled && isMouseDown && e.LeftButton == MouseButtonState.Pressed && Manager != null) + // The MouseLeave event can occur if the managed content was closed while the user held the left mouse button pressed. + // In that case, this.IsLoaded will be false and we won't handle the event + if (!e.Handled && isMouseDown && e.LeftButton == MouseButtonState.Pressed && Manager != null && this.IsLoaded) { if (!IsMouseCaptured) {