Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs32
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/DotNetCoreProjectTests.cs38
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs26
3 files changed, 96 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
index b3f0717fdb..8c53b0504d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
@@ -74,14 +74,22 @@ namespace MonoDevelop.Projects
BuildAction = buildAction;
}
+ string cachedInclude;
+
public override string Include {
get {
if (Project != null) {
+ if (cachedInclude != null)
+ return cachedInclude;
+
string path = MSBuildProjectService.ToMSBuildPath (Project.ItemDirectory, FilePath);
if (path.Length > 0) {
//directory paths must end with '/'
if ((Subtype == Subtype.Directory) && path [path.Length - 1] != '\\')
path = path + "\\";
+ // Cache the include path to avoid recalculating MSBuildProjectService.ToMSBuildPath
+ // which can slow down saving SDK style projects that contain thousands of files.
+ cachedInclude = path;
return path;
}
}
@@ -186,6 +194,8 @@ namespace MonoDevelop.Projects
if (IsLink && Link.FileName == oldPath.FileName)
link = Path.Combine (Path.GetDirectoryName (link), filename.FileName);
+ cachedInclude = null;
+
// If a file that belongs to a project is being renamed, update the value of UnevaluatedInclude
// since that is used when saving
if (Project != null)
@@ -474,15 +484,33 @@ namespace MonoDevelop.Projects
}
}
+ Project project;
+
protected override void OnProjectSet ()
{
base.OnProjectSet ();
+ if (project != null) {
+ project.Modified -= OnProjectModified;
+ project = null;
+ }
if (Project != null) {
base.Include = Include;
+ project = Project;
+ project.Modified += OnProjectModified;
VirtualPathChanged?.Invoke (this, new ProjectFileVirtualPathChangedEventArgs (this, FilePath.Null, ProjectVirtualPath));
}
}
+ void OnProjectModified (object sender, SolutionItemModifiedEventArgs e)
+ {
+ foreach (var eventInfo in e) {
+ if (eventInfo.Hint == "FileName") {
+ cachedInclude = null;
+ return;
+ }
+ }
+ }
+
public override string ToString ()
{
return "[ProjectFile: FileName=" + filename + "]";
@@ -503,6 +531,10 @@ namespace MonoDevelop.Projects
public virtual void Dispose ()
{
+ if (project != null) {
+ project.Modified -= OnProjectModified;
+ project = null;
+ }
}
internal event EventHandler<ProjectFileVirtualPathChangedEventArgs> VirtualPathChanged;
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/DotNetCoreProjectTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/DotNetCoreProjectTests.cs
index 86a3aadfc2..0ba1113eb9 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/DotNetCoreProjectTests.cs
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/DotNetCoreProjectTests.cs
@@ -696,6 +696,44 @@ namespace MonoDevelop.Projects
}
}
+ [Test]
+ public async Task AddNewFileToProjectAndSave_ProjectHas1500CSharpFiles_SavingIsFast ()
+ {
+ FilePath solFile = Util.GetSampleProject ("netstandard-sdk", "netstandard-sdk.sln");
+
+ // Create 1500 C# files.
+ var sourceDirectory = solFile.ParentDirectory.Combine ("Files");
+ Directory.CreateDirectory (sourceDirectory);
+
+ for (int i = 0; i < 1500; ++i) {
+ string fileName = sourceDirectory.Combine ($"Test{i}.cs");
+ string code = "class Test" + i + "{}";
+ File.WriteAllText (fileName, code);
+ }
+
+ using (var solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solFile)) {
+ var p = solution.GetAllProjects ().Single () as DotNetProject;
+ // Sanity check - ensure project and solution in same directory otherwise the generated .cs files
+ // will not be used.
+ Assert.AreEqual (solution.BaseDirectory, p.BaseDirectory);
+
+ string fileName = p.BaseDirectory.Combine ("NewClass.cs");
+ string code = "class NewClass {}";
+ File.WriteAllText (fileName, code);
+
+ p.AddFile (fileName, BuildAction.Compile);
+
+ var timer = Stopwatch.StartNew ();
+ await p.SaveAsync (Util.GetMonitor ());
+ timer.Stop ();
+
+ // This was taking 20 seconds before.
+ // Takes about 300ms with ProjectFile.Include caching. Here we use 2 seconds
+ // in case the build server is slow.
+ Assert.That (timer.ElapsedMilliseconds, Is.LessThan (2000));
+ }
+ }
+
static void RunMSBuildRestore (FilePath fileName)
{
CreateNuGetConfigFile (fileName.ParentDirectory);
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs
index e44b98f5c6..0913f550de 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/ProjectTests.cs
@@ -1226,6 +1226,32 @@ namespace MonoDevelop.Projects
}
}
+ /// <summary>
+ /// Ensure the cached value is updated when the Project or FileName changes.
+ /// </summary>
+ [Test]
+ public void ProjectFileIncludeCachingTests ()
+ {
+ using (var project = Services.ProjectService.CreateDotNetProject ("C#")) {
+ FilePath directory = Util.CreateTmpDir ("ProjectFileIncludeCachingTests");
+ project.FileName = directory.Combine ("Project.csproj");
+
+ var fileName = project.BaseDirectory.Combine ("Source", "Test.cs");
+ var projectFile = new ProjectFile (fileName);
+ projectFile.Project = project;
+
+ Assert.AreEqual (@"Source\Test.cs", projectFile.Include);
+
+ projectFile.Name = projectFile.FilePath.ChangeName ("Changed");
+ Assert.AreEqual (@"Source\Changed.cs", projectFile.Include);
+ Assert.AreEqual (@"Source\Changed.cs", projectFile.UnevaluatedInclude);
+
+ // Change project's ItemDirectory. This will change the ProjectFile's Include.
+ project.FileName = project.BaseDirectory.Combine ("Source", "Project.csproj");
+ Assert.AreEqual ("Changed.cs", projectFile.Include);
+ }
+ }
+
class TestGetReferencesProjectExtension : DotNetProjectExtension
{
protected internal override Task<List<AssemblyReference>> OnGetReferences (ConfigurationSelector configuration, CancellationToken token)