diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2012-05-23 12:47:04 +0400 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2012-05-23 12:47:04 +0400 |
commit | 7eb52d7b473a4c128b0462771acb2654fd303477 (patch) | |
tree | 571c7e5baabaf893c278f84482f4ae1e7baa1d0b /main/src | |
parent | 55224d5f44ef72491e2d15c62920d423165436c4 (diff) |
Fixed 'Bug 4750 - Comment tasks no longer work'. The project cache
from the type system service can now be extended with meta data.
Diffstat (limited to 'main/src')
6 files changed, 221 insertions, 19 deletions
diff --git a/main/src/core/MonoDevelop.Ide/Makefile.am b/main/src/core/MonoDevelop.Ide/Makefile.am index 74fe12890e..3bc36179de 100644 --- a/main/src/core/MonoDevelop.Ide/Makefile.am +++ b/main/src/core/MonoDevelop.Ide/Makefile.am @@ -691,6 +691,7 @@ FILES = \ MonoDevelop.Ide.TypeSystem/OutputSettings.cs \ MonoDevelop.Ide.TypeSystem/ParsedDocument.cs \ MonoDevelop.Ide.TypeSystem/PreProcessorDefine.cs \ + MonoDevelop.Ide.TypeSystem/ProjectCommentTags.cs \ MonoDevelop.Ide.TypeSystem/ProjectContentEventArgs.cs \ MonoDevelop.Ide.TypeSystem/StockIcons.cs \ MonoDevelop.Ide.TypeSystem/Tag.cs \ diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksView.cs index a3214c193b..620076db39 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksView.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksView.cs @@ -195,11 +195,18 @@ namespace MonoDevelop.Ide.Tasks // Load all tags that are stored in pidb files foreach (Project p in sln.GetAllProjects ()) { - var pContext = TypeSystemService.GetProjectContext (p); + var pContext = TypeSystemService.GetProjectContentWrapper (p); if (pContext == null) continue; - foreach (ProjectFile file in p.Files) { - UpdateCommentTags (sln, file.Name, GetSpecialComments (pContext, file.Name)); + var tags = pContext.GetExtensionObject<ProjectCommentTags> (); + if (tags == null) { + tags = new ProjectCommentTags (); + pContext.UpdateExtensionObject (tags); + tags.Update (pContext.Project); + } else { + foreach (var kv in tags.Tags) { + UpdateCommentTags (sln, kv.Key, kv.Value); + } } } } @@ -225,8 +232,11 @@ namespace MonoDevelop.Ide.Tasks //because of parse queueing, it's possible for this event to come in after the solution is closed //so we track which solutions are currently open so that we don't leak memory by holding // on to references to closed projects - if (e.Project != null && e.Project.ParentSolution != null && loadedSlns.Contains (e.Project.ParentSolution)) - UpdateCommentTags (e.Project.ParentSolution, e.FileName, e.TagComments); + if (e.Project != null && e.Project.ParentSolution != null && loadedSlns.Contains (e.Project.ParentSolution)) { + Application.Invoke (delegate { + UpdateCommentTags (e.Project.ParentSolution, e.FileName, e.TagComments); + }); + } } void OnCommentTagsChanged (object sender, EventArgs e) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs index a209e06e22..e29aefd2d3 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs @@ -183,6 +183,13 @@ namespace MonoDevelop.Ide.Tasks if (handler != null) handler (null, new TaskEventArgs (task)); } + + internal static void InformCommentTasks (CommentTasksChangedEventArgs args) + { + var handler = CommentTasksChanged; + if (handler != null) + handler (null, args); + } public static event EventHandler<CommentTasksChangedEventArgs> CommentTasksChanged; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ProjectCommentTags.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ProjectCommentTags.cs new file mode 100644 index 0000000000..dad1ebe4bb --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ProjectCommentTags.cs @@ -0,0 +1,80 @@ +// +// ProjectCommentTags.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using MonoDevelop.Projects; +using MonoDevelop.Ide.Tasks; + +namespace MonoDevelop.Ide.TypeSystem +{ + [Serializable] + public class ProjectCommentTags + { + readonly Dictionary<string, List<Tag>> tags = new Dictionary<string, List<Tag>> (); + + public IDictionary<string, List<Tag>> Tags { + get { + return tags; + } + } + + public void UpdateTags (Project project, string fileName, IList<Tag> tagComments) + { + var list = tagComments == null || tagComments.Count == 0 ? null : new List<Tag> (tagComments); + lock (tags) { + List<Tag> oldList; + tags.TryGetValue (fileName, out oldList); + if (list == null && oldList == null) + return; + tags[fileName] = list; + TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (fileName, tagComments, project)); + } + } + + public void RemoveFile (Project project, string fileName) + { + lock (tags) { + if (!tags.ContainsKey (fileName)) + return; + tags[fileName] = null; + } + + TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (fileName, null, project)); + } + + public void Update (Project project) + { + System.Threading.Tasks.Task.Factory.StartNew (delegate { + foreach (var file in project.Files) { + TypeSystemService.ParseFile (project, file.FilePath); + } + }); + } + } +} + diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs index fc1743f065..b72bd5dd06 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs @@ -257,6 +257,7 @@ namespace MonoDevelop.Ide.TypeSystem } if (wrapper != null && (result.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) { wrapper.UpdateContent (c => c.UpdateProjectContent (c.GetFile (fileName), result.ParsedFile)); + UpdateParsedDocument (wrapper, result); } // The parsed file could be included in other projects as well, therefore @@ -303,8 +304,10 @@ namespace MonoDevelop.Ide.TypeSystem try { var result = parser.Parse (true, fileName, content); lock (projectWrapperUpdateLock) { - if (wrapper != null && (result.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) + if (wrapper != null && (result.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) { wrapper.UpdateContent (c => c.UpdateProjectContent (c.GetFile (fileName), result.ParsedFile)); + UpdateParsedDocument (wrapper, result); + } } return result; } catch (Exception e) { @@ -522,7 +525,26 @@ namespace MonoDevelop.Ide.TypeSystem LoggingService.LogError ("Error while touching cache directory " + cacheDir, e); } } - + + static void StoreExtensionObject (string cacheDir, object extensionObject) + { + if (cacheDir == null) + throw new ArgumentNullException ("cacheDir"); + if (extensionObject == null) + throw new ArgumentNullException ("extensionObject"); + var fileName = Path.GetTempFileName (); + SerializeObject (fileName, extensionObject); + var cacheFile = Path.Combine (cacheDir, extensionObject.GetType ().FullName + ".cache"); + + try { + if (File.Exists (cacheFile)) + File.Delete (cacheFile); + File.Move (fileName, cacheFile); + } catch (Exception e) { + LoggingService.LogError ("Error whil saving cache " + cacheFile + " for extension object:"+ extensionObject, e); + } + } + static void StoreProjectCache (Project project, ProjectContentWrapper wrapper) { if (!wrapper.WasChanged) @@ -538,11 +560,14 @@ namespace MonoDevelop.Ide.TypeSystem try { if (File.Exists (cacheFile)) System.IO.File.Delete (cacheFile); - System.IO.File.Move (fileName, cacheFile); } catch (Exception e) { LoggingService.LogError ("Error whil saving cache " + cacheFile, e); } + + foreach (var extensionObject in wrapper.ExtensionObjects) { + StoreExtensionObject (cacheDir, extensionObject); + } } #endregion @@ -646,13 +671,71 @@ namespace MonoDevelop.Ide.TypeSystem public class ProjectContentWrapper { IProjectContent content; - + Dictionary<Type, object> extensionObjects = new Dictionary<Type, object> (); + public IProjectContent Content { get { return content; } } - + + /// <summary> + /// Gets the extension objects attached to the content wrapper. + /// </summary> + public IEnumerable<object> ExtensionObjects { + get { + return extensionObjects.Values; + } + } + + /// <summary> + /// Updates an extension object for the wrapper. Note that only one extension object of a certain + /// type may be stored inside the project content wrapper. + /// + /// The extension objects need to be serializable and are stored in the project cache on project unload. + /// </summary> + public void UpdateExtensionObject (object ext) + { + if (ext == null) + throw new ArgumentNullException ("ext"); + extensionObjects[ext.GetType ()] = ext; + } + + /// <summary> + /// Gets a specific extension object. This may lazy load an existing extension object from disk, + /// if called the first time and a serialized extension object exists. + /// </summary> + /// <returns> + /// The extension object. Or null, if no extension object of the specified type was registered. + /// </returns> + /// <typeparam name='T'> + /// The type of the extension object. + /// </typeparam> + public T GetExtensionObject<T> () where T : class + { + object result; + if (extensionObjects.TryGetValue (typeof (T), out result)) + return (T)result; + + string cacheDir = GetCacheDirectory (Project.FileName); + if (cacheDir == null) + return default(T); + + try { + string fileName = Path.Combine (cacheDir, typeof (T).FullName + ".cache"); + if (File.Exists (fileName)) { + Console.WriteLine ("deserialize :" + fileName); + var deserialized = DeserializeObject<T> (fileName); + extensionObjects[typeof(T)] = deserialized; + return deserialized; + } + } catch (Exception) { + Console.WriteLine ("Can't deserialize :" + typeof (T).FullName); + } + + return default (T); + } + public void UpdateContent (Func<IProjectContent, IProjectContent> updateFunc) { lock (this) { @@ -980,7 +1063,12 @@ namespace MonoDevelop.Ide.TypeSystem { var project = (Project)sender; foreach (ProjectFileEventInfo fargs in args) { - projectContents [project].UpdateContent (c => c.UpdateProjectContent (c.GetFile (fargs.ProjectFile.Name), null)); + var wrapper = projectContents [project]; + var fileName = fargs.ProjectFile.Name; + wrapper.UpdateContent (c => c.UpdateProjectContent (c.GetFile (fileName), null)); + var tags = wrapper.GetExtensionObject <ProjectCommentTags> (); + if (tags != null) + tags.RemoveFile (wrapper.Project, fileName); } } @@ -1589,6 +1677,7 @@ namespace MonoDevelop.Ide.TypeSystem continue; using (var stream = new System.IO.StreamReader (fileName)) { var parsedDocument = parser.Parse (false, fileName, stream, Context.Project); + UpdateParsedDocument (Context, parsedDocument); Context.UpdateContent (c => c.UpdateProjectContent (c.GetFile (fileName), parsedDocument.ParsedFile)); } } @@ -1596,6 +1685,17 @@ namespace MonoDevelop.Ide.TypeSystem } } + static void UpdateParsedDocument (ProjectContentWrapper context, ParsedDocument parsedDocument) + { + var tags = context.GetExtensionObject <ProjectCommentTags> (); + if (tags == null) { + tags = new ProjectCommentTags (); + context.UpdateExtensionObject (tags); + tags.Update (context.Project); + } + tags.UpdateTags (context.Project, parsedDocument.FileName, parsedDocument.TagComments); + } + public static event EventHandler<ProjectFileEventArgs> FileParsed; static object parseQueueLock = new object (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index 957b7a1c27..9ea3e7c521 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -44,18 +44,23 @@ <Reference Include="monodoc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" /> <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> <SpecificVersion>False</SpecificVersion> + <Package>gtk-sharp-2.0</Package> </Reference> <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> <SpecificVersion>False</SpecificVersion> + <Package>gtk-sharp-2.0</Package> </Reference> <Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> <SpecificVersion>False</SpecificVersion> + <Package>gtk-sharp-2.0</Package> </Reference> <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> <SpecificVersion>False</SpecificVersion> + <Package>glib-sharp-2.0</Package> </Reference> <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> <SpecificVersion>False</SpecificVersion> + <Package>gtk-sharp-2.0</Package> </Reference> <Reference Include="System.Core" /> <Reference Include="ICSharpCode.SharpZipLib" /> @@ -64,12 +69,18 @@ <Reference Include="System.Xml.Linq" /> <Reference Include="Mono.Addins.Gui, Version=0.5.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"> <SpecificVersion>False</SpecificVersion> + <Package>mono-addins-gui</Package> </Reference> <Reference Include="Mono.Addins, Version=0.5.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"> <SpecificVersion>False</SpecificVersion> + <Package>mono-addins</Package> </Reference> <Reference Include="Mono.Addins.Setup, Version=0.5.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"> <SpecificVersion>False</SpecificVersion> + <Package>mono-addins-setup</Package> + </Reference> + <Reference Include="Mono.Cecil"> + <HintPath>..\..\..\build\bin\Mono.Cecil.dll</HintPath> </Reference> </ItemGroup> <ItemGroup> @@ -97,14 +108,6 @@ <Name>ICSharpCode.NRefactory.CSharp</Name> <Private>False</Private> </ProjectReference> - <ProjectReference Include="..\..\..\external\cecil\Mono.Cecil.csproj"> - <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project> - <Name>Mono.Cecil</Name> - </ProjectReference> - <ProjectReference Include="..\..\..\external\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj"> - <Project>{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}</Project> - <Name>Mono.Cecil.Mdb</Name> - </ProjectReference> </ItemGroup> <ItemGroup> <EmbeddedResource Include="templates\AppConfigFile.xft.xml"> @@ -1516,6 +1519,7 @@ <Compile Include="MonoDevelop.Ide.TypeSystem\MonoDocDocumentationProvider.cs" /> <Compile Include="MonoDevelop.Ide.Projects.OptionPanels\PortableRuntimeOptionsPanel.cs" /> <Compile Include="gtk-gui\MonoDevelop.Ide.Projects.OptionPanels.PortableRuntimeOptionsPanelWidget.cs" /> + <Compile Include="MonoDevelop.Ide.TypeSystem\ProjectCommentTags.cs" /> </ItemGroup> <ItemGroup> <None Include="Makefile.am" /> |