diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs index a222676ecf..3e96099c05 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs @@ -14,6 +14,7 @@ namespace ICSharpCode.AvalonEdit.Document public sealed class RopeTextSource : ITextSource { readonly Rope rope; + readonly ITextSourceVersion version; /// /// Creates a new RopeTextSource. @@ -22,7 +23,18 @@ namespace ICSharpCode.AvalonEdit.Document { if (rope == null) throw new ArgumentNullException("rope"); - this.rope = rope; + this.rope = rope.Clone(); + } + + /// + /// Creates a new RopeTextSource. + /// + public RopeTextSource(Rope rope, ITextSourceVersion version) + { + if (rope == null) + throw new ArgumentNullException("rope"); + this.rope = rope.Clone(); + this.version = version; } /// @@ -30,7 +42,6 @@ namespace ICSharpCode.AvalonEdit.Document /// /// /// RopeTextSource only publishes a copy of the contained rope to ensure that the underlying rope cannot be modified. - /// Unless the creator of the RopeTextSource still has a reference on the rope, RopeTextSource is immutable. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Not a property because it creates a clone")] public Rope GetRope() @@ -75,8 +86,7 @@ namespace ICSharpCode.AvalonEdit.Document /// public ITextSource CreateSnapshot() { - // we clone the underlying rope because the creator of the RopeTextSource might be modifying it - return new RopeTextSource(rope.Clone()); + return this; } /// @@ -91,8 +101,9 @@ namespace ICSharpCode.AvalonEdit.Document return rope.IndexOfAny(anyOf, startIndex, count); } - ITextSourceVersion ITextSource.Version { - get { return null; } + /// + public ITextSourceVersion Version { + get { return version; } } string ITextSource.GetText(ICSharpCode.Editor.ISegment segment) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs index 37ff1f7270..8388a69a25 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs @@ -298,7 +298,9 @@ namespace ICSharpCode.AvalonEdit.Document public ITextSource CreateSnapshot() { lock (lockObject) { - return new RopeTextSource(rope.Clone()); + if (currentCheckpoint == null) + currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); + return new RopeTextSource(rope, currentCheckpoint); } } @@ -325,7 +327,7 @@ namespace ICSharpCode.AvalonEdit.Document if (currentCheckpoint == null) currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); checkpoint = currentCheckpoint; - return new RopeTextSource(rope.Clone()); + return new RopeTextSource(rope, currentCheckpoint); } } @@ -927,6 +929,7 @@ namespace ICSharpCode.AvalonEdit.Document var container = new ServiceContainer(); container.AddService(typeof(IDocument), this); container.AddService(typeof(TextDocument), this); + serviceProvider = container; } return serviceProvider; } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/GotoDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/GotoDialog.cs index 4fd6e7ee2d..4c7193089c 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/GotoDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/GotoDialog.cs @@ -2,19 +2,15 @@ // 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.ComponentModel; using System.IO; -using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; + using ICSharpCode.Core; -using ICSharpCode.Core.Presentation; -using ICSharpCode.Editor; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; diff --git a/src/Main/Base/Project/Src/Project/CompilableProject.cs b/src/Main/Base/Project/Src/Project/CompilableProject.cs index bb45932c1e..0c8bc3e3fb 100644 --- a/src/Main/Base/Project/Src/Project/CompilableProject.cs +++ b/src/Main/Base/Project/Src/Project/CompilableProject.cs @@ -10,6 +10,9 @@ using System.Linq; using System.Runtime.InteropServices.ComTypes; using System.Xml.Linq; using ICSharpCode.Core; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Project.Converter; using ICSharpCode.SharpDevelop.Util; @@ -403,6 +406,10 @@ namespace ICSharpCode.SharpDevelop.Project void Reparse(bool references, bool code) { + lock (SyncRoot) { + if (parseProjectContent == null) + return; // parsing hasn't started yet; no need to re-parse + } #warning Reparse throw new NotImplementedException(); } @@ -643,5 +650,28 @@ namespace ICSharpCode.SharpDevelop.Project } } #endregion + + #region Type System + volatile ParseProjectContent parseProjectContent; + + public override IProjectContent ProjectContent { + get { + if (parseProjectContent == null) { + lock (SyncRoot) { + if (parseProjectContent == null) { + parseProjectContent = new ParseProjectContent(this); + } + } + } + return parseProjectContent; + } + } + + public override ITypeResolveContext TypeResolveContext { + get { + return new CompositeTypeResolveContext(new ITypeResolveContext[] { this.ProjectContent, MinimalResolveContext.Instance }); + } + } + #endregion } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index bd5500fb94..85d849a132 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -7,130 +7,114 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; - using ICSharpCode.Core; +using ICSharpCode.Editor; +using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; -/* + namespace ICSharpCode.SharpDevelop.Parser { - public sealed class ParseProjectContent : DefaultProjectContent + public class ParseProjectContent : SimpleProjectContent, IDisposable { + readonly IProject project; + readonly object lockObj = new object(); + bool initializing; + bool disposed; + public ParseProjectContent(IProject project) { if (project == null) throw new ArgumentNullException("project"); this.project = project; - this.Language = project.LanguageProperties; + this.initializing = true; + LoadSolutionProjects.AddJob(Initialize, "Loading " + project.Name + "...", GetInitializationWorkAmount()); } - readonly IProject project; - - public override object Project { - get { - return project; + public void Dispose() + { + lock (lockObj) { + ProjectService.ProjectItemAdded -= OnProjectItemAdded; + ProjectService.ProjectItemRemoved -= OnProjectItemRemoved; + disposed = true; } - } - - public string ProjectName { - get { return project.Name; } + initializing = false; } public override string AssemblyName { get { return project.AssemblyName; } } - bool initializing; - public override string ToString() { return string.Format("[{0}: {1}]", GetType().Name, project.Name); } - internal void Initialize1(IProgressMonitor progressMonitor) + int GetInitializationWorkAmount() { - ICollection items = project.Items; - ProjectService.ProjectItemAdded += OnProjectItemAdded; - ProjectService.ProjectItemRemoved += OnProjectItemRemoved; - UpdateDefaultImports(items); - // TODO: Translate me -// progressMonitor.TaskName = "Resolving references for " + project.Name + "..."; - project.ResolveAssemblyReferences(); - foreach (ProjectItem item in items) { - if (!initializing) return; // abort initialization - progressMonitor.CancellationToken.ThrowIfCancellationRequested(); - if (ItemType.ReferenceItemTypes.Contains(item.ItemType)) { - ReferenceProjectItem reference = item as ReferenceProjectItem; - if (reference != null) { - // TODO: Translate me -// progressMonitor.TaskName = "Loading " + reference.ShortName + "..."; - AddReference(reference, false, progressMonitor.CancellationToken); - } - } - } - UpdateReferenceInterDependencies(); - OnReferencedContentsChanged(EventArgs.Empty); + return project.Items.Count + 15; } - internal void ReInitialize1(IProgressMonitor progressMonitor) + void Initialize(IProgressMonitor progressMonitor) { - var mscorlib = AssemblyParserService.GetRegistryForReference(new ReferenceProjectItem(project, "mscorlib")).Mscorlib; - // don't fetch mscorlib within lock - finding the correct registry might access the project, causing - // a deadlock between IProject.SyncRoot and the ReferencedContents lock - lock (ReferencedContents) { - ReferencedContents.Clear(); - AddReferencedContent(mscorlib); + ICollection projectItems = project.Items; + lock (lockObj) { + if (disposed) { + throw new ObjectDisposedException("ParseProjectContent"); + } + ProjectService.ProjectItemAdded += OnProjectItemAdded; + ProjectService.ProjectItemRemoved += OnProjectItemRemoved; } - // prevent adding event handler twice - ProjectService.ProjectItemAdded -= OnProjectItemAdded; - ProjectService.ProjectItemRemoved -= OnProjectItemRemoved; - initializing = true; - try { - Initialize1(progressMonitor); - } finally { - initializing = false; + using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(15), + parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count)) + { + var resolveReferencesTask = ResolveReferencesAsync(projectItems, initReferencesProgressMonitor); + + ParseFiles(projectItems, parseProgressMonitor); + + resolveReferencesTask.Wait(); } } - void UpdateReferenceInterDependencies() + void ParseFiles(ICollection projectItems, IProgressMonitor progressMonitor) { - // Use ToArray because the collection could be modified inside the loop - IProjectContent[] referencedContents; - lock (this.ReferencedContents) { - referencedContents = new IProjectContent[this.ReferencedContents.Count]; - this.ReferencedContents.CopyTo(referencedContents, 0); - } - foreach (IProjectContent referencedContent in referencedContents) { - if (referencedContent is ReflectionProjectContent) { - ((ReflectionProjectContent)referencedContent).InitializeReferences(); + ParseableFileContentFinder finder = new ParseableFileContentFinder(); + var fileContents = ( + from p in projectItems.AsParallel().WithCancellation(progressMonitor.CancellationToken) + where !ItemType.NonFileItemTypes.Contains(p.ItemType) && !String.IsNullOrEmpty(p.FileName) + select FileName.Create(p.FileName) + ).ToList(); + + object progressLock = new object(); + double fileCountInverse = 1.0 / fileContents.Count; + Parallel.ForEach( + fileContents, + new ParallelOptions { + MaxDegreeOfParallelism = Environment.ProcessorCount, + CancellationToken = progressMonitor.CancellationToken + }, + fileName => { + // Don't read files we don't have a parser for. + // This avoids loading huge files (e.g. sdps) when we have no intention of parsing them. + if (ParserService.GetParser(fileName) != null) { + ITextSource content = finder.Create(fileName); + if (content != null) + ParserService.ParseFile(this, fileName, content); + } + lock (progressLock) { + progressMonitor.Progress += fileCountInverse; + } } - } + ); } - void AddReference(ReferenceProjectItem reference, bool updateInterDependencies, CancellationToken cancellationToken) + System.Threading.Tasks.Task ResolveReferencesAsync(ICollection projectItems, IProgressMonitor progressMonitor) { - try { - AddReferencedContent(AssemblyParserService.GetProjectContentForReference(reference)); - if (updateInterDependencies) { - UpdateReferenceInterDependencies(); - } - OnReferencedContentsChanged(EventArgs.Empty); - - // Refresh the reference if required. - // If the user removes the reference and then re-adds it, there might be other references - // in the project depending on it, so we do the refresh after the old reference was added. - AssemblyParserService.RefreshProjectContentForReference(reference); - } catch (OperationCanceledException) { - throw; - } catch (ObjectDisposedException e) { - // ObjectDisposedException can happen if project gets disposed while LoadSolutionProjectsThread is running. - // We will ignore the ObjectDisposedException and throw OperationCanceledException instead. - cancellationToken.ThrowIfCancellationRequested(); - MessageService.ShowException(e); - } catch (Exception e) { - MessageService.ShowException(e); - } + return System.Threading.Tasks.Task.Factory.StartNew( + delegate { + project.ResolveAssemblyReferences(); + }, progressMonitor.CancellationToken); } // ensure that com references are built serially because we cannot invoke multiple instances of MSBuild @@ -149,13 +133,13 @@ namespace ICSharpCode.SharpDevelop.Parser project.Save(); // project is not yet saved when ItemAdded fires, so save it here TaskService.BuildMessageViewCategory.AppendText("\n${res:MainWindow.CompilerMessages.CreatingCOMInteropAssembly}\n"); BuildCallback afterBuildCallback = delegate { + ReparseReferences(); lock (callAfterAddComReference) { if (callAfterAddComReference.Count > 0) { // run next enqueued action callAfterAddComReference.Dequeue()(); } else { buildingComReference = false; - ParserService.Reparse(project, true, false); } } }; @@ -173,18 +157,24 @@ namespace ICSharpCode.SharpDevelop.Parser } } } else { - ParserService.Reparse(project, true, false); + ReparseReferences(); } } if (e.ProjectItem.ItemType == ItemType.Import) { - UpdateDefaultImports(project.Items); + throw new NotImplementedException(); + //UpdateDefaultImports(project.Items); } else if (e.ProjectItem.ItemType == ItemType.Compile) { if (System.IO.File.Exists(e.ProjectItem.FileName)) { - ParserService.BeginParse(e.ProjectItem.FileName); + ParserService.ParseFileAsync(FileName.Create(e.ProjectItem.FileName)); } } } + void ReparseReferences() + { + throw new NotImplementedException(); + } + void OnProjectItemRemoved(object sender, ProjectItemEventArgs e) { if (e.Project != project) return; @@ -192,25 +182,21 @@ namespace ICSharpCode.SharpDevelop.Parser ReferenceProjectItem reference = e.ProjectItem as ReferenceProjectItem; if (reference != null) { try { - IProjectContent referencedContent = AssemblyParserService.GetExistingProjectContentForReference(reference); - if (referencedContent != null) { - lock (ReferencedContents) { - ReferencedContents.Remove(referencedContent); - } - OnReferencedContentsChanged(EventArgs.Empty); - } + ReparseReferences(); } catch (Exception ex) { MessageService.ShowException(ex); } } if (e.ProjectItem.ItemType == ItemType.Import) { - UpdateDefaultImports(project.Items); + throw new NotImplementedException(); + //UpdateDefaultImports(project.Items); } else if (e.ProjectItem.ItemType == ItemType.Compile) { - ParserService.ClearParseInformation(e.ProjectItem.FileName); + ParserService.ClearParseInformation(FileName.Create(e.ProjectItem.FileName)); } } + /* int languageDefaultImportCount = -1; void UpdateDefaultImports(ICollection items) @@ -233,77 +219,6 @@ namespace ICSharpCode.SharpDevelop.Parser DefaultImports.Usings.Add(item.Include); } } - } - - internal int GetInitializationWorkAmount() - { - return project.Items.Count; - } - - internal void ReInitialize2(IProgressMonitor progressMonitor) - { - if (initializing) return; - initializing = true; - Initialize2(progressMonitor); - } - - internal void Initialize2(IProgressMonitor progressMonitor) - { - if (!initializing) return; - try { - IProjectContent[] referencedContents; - lock (this.ReferencedContents) { - referencedContents = new IProjectContent[this.ReferencedContents.Count]; - this.ReferencedContents.CopyTo(referencedContents, 0); - } - - foreach (IProjectContent referencedContent in referencedContents) { - if (referencedContent is ReflectionProjectContent) { - ((ReflectionProjectContent)referencedContent).InitializeReferences(); - } - } - - ParseableFileContentFinder finder = new ParseableFileContentFinder(); - var fileContents = ( - from p in project.Items.AsParallel().WithCancellation(progressMonitor.CancellationToken) - where !ItemType.NonFileItemTypes.Contains(p.ItemType) && !String.IsNullOrEmpty(p.FileName) - select FileName.Create(p.FileName) - ).ToList(); - - object progressLock = new object(); - double fileCountInverse = 1.0 / fileContents.Count; - Parallel.ForEach( - fileContents, - new ParallelOptions { - MaxDegreeOfParallelism = Environment.ProcessorCount * 2, - CancellationToken = progressMonitor.CancellationToken - }, - fileName => { - // Don't read files we don't have a parser for. - // This avoids loading huge files (e.g. sdps) when we have no intention of parsing them. - if (ParserService.GetParser(fileName) != null) { - ITextBuffer content = finder.Create(fileName); - if (content != null) - ParserService.ParseFile(this, fileName, content); - } - lock (progressLock) { - progressMonitor.Progress += fileCountInverse; - } - } - ); - } finally { - initializing = false; - progressMonitor.Progress = 1; - } - } - - public override void Dispose() - { - ProjectService.ProjectItemAdded -= OnProjectItemAdded; - ProjectService.ProjectItemRemoved -= OnProjectItemRemoved; - initializing = false; - base.Dispose(); - } + }*/ } } -*/ diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 2c55750c51..ff65c15fa6 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -1033,6 +1033,9 @@ namespace ICSharpCode.SharpDevelop.Parser internal static void OnSolutionLoaded() { + foreach (IProject project in ProjectService.OpenSolution.Projects) { + RegisterProjectContentForAddedProject(project); + } } internal static void OnSolutionClosed()