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
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MetadataReferenceCache.cs')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MetadataReferenceCache.cs166
1 files changed, 166 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MetadataReferenceCache.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MetadataReferenceCache.cs
new file mode 100644
index 0000000000..77d8e818eb
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MetadataReferenceCache.cs
@@ -0,0 +1,166 @@
+//
+// MetadataReferenceCache.cs
+//
+// Author:
+// David Karlaš <david.karlas@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin, Inc (http://www.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 Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.IO;
+using MonoDevelop.Core;
+using System.Threading;
+
+namespace MonoDevelop.Ide.TypeSystem
+{
+ static class MetadataReferenceCache
+ {
+ static Dictionary<string, MetadataReferenceCacheItem> cache = new Dictionary<string, MetadataReferenceCacheItem> ();
+
+ public static MetadataReference LoadReference (ProjectId projectId, string path)
+ {
+ lock (cache) {
+ MetadataReferenceCacheItem result;
+ if (!cache.TryGetValue (path, out result)) {
+ result = new MetadataReferenceCacheItem (path);
+ cache.Add (path, result);
+ }
+ result.InUseBy.Add (projectId);
+ return result.Reference;
+ }
+ }
+
+ //TODO: This should be called when reference is actually removed and not on
+ //project reload because if this is only project that has this reference... Cache will be
+ //invalidated and when reload comes back in few miliseconds it will need to reload reference again
+ public static void RemoveReference (ProjectId projectId, string path)
+ {
+ lock (cache) {
+ MetadataReferenceCacheItem result;
+ if (cache.TryGetValue (path, out result)) {
+ result.InUseBy.Remove (projectId);
+ if (result.InUseBy.Count == 0) {
+ cache.Remove (path);
+ }
+ }
+ }
+ }
+
+ public static void RemoveReferences (ProjectId id)
+ {
+ lock (cache) {
+ var toRemove = new List<string> ();
+ foreach (var val in cache) {
+ val.Value.InUseBy.Remove (id);
+ if (val.Value.InUseBy.Count == 0) {
+ toRemove.Add (val.Key);
+ }
+ }
+ toRemove.ForEach ((k) => cache.Remove (k));
+ }
+ }
+
+ static Timer timer;
+
+ static MetadataReferenceCache ()
+ {
+ timer = new Timer ((o) => CheckForChanges (), null, 10000, 10000);
+ }
+
+ //TODO: Call this method when focus returns to MD or even better use FileSystemWatcher
+ public static void CheckForChanges ()
+ {
+ lock (cache) {
+ foreach (var value in cache.Values) {
+ value.CheckForChange ();
+ }
+ }
+ }
+
+ class MetadataReferenceCacheItem
+ {
+ public HashSet<ProjectId> InUseBy { get; private set; }
+
+ public MetadataReference Reference { get; private set; }
+
+ readonly string path;
+
+ DateTime timeStamp;
+
+ public MetadataReferenceCacheItem (string path)
+ {
+ this.path = path;
+ CreateNewReference ();
+ InUseBy = new HashSet<ProjectId> ();
+ }
+
+ public void CheckForChange ()
+ {
+ if (timeStamp != File.GetLastWriteTimeUtc (path)) {
+ if (Reference != null) {
+ foreach (var solution in IdeApp.Workspace.GetAllSolutions ()) {
+ var workspace = TypeSystemService.GetWorkspace (solution);
+ foreach (var projId in InUseBy) {
+ while (true) {
+ var project = workspace.CurrentSolution.GetProject (projId);
+ if (project == null)
+ break;
+ if (workspace.TryApplyChanges (project.RemoveMetadataReference (Reference).Solution))
+ break;
+ }
+ }
+ }
+ }
+ CreateNewReference ();
+ if (Reference != null) {
+ foreach (var solution in IdeApp.Workspace.GetAllSolutions ()) {
+ var workspace = TypeSystemService.GetWorkspace (solution);
+ foreach (var projId in InUseBy) {
+ while (true) {
+ var project = workspace.CurrentSolution.GetProject (projId);
+ if (project == null)
+ break;
+ if (workspace.TryApplyChanges (project.AddMetadataReference (Reference).Solution))
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ readonly static DateTime NonExistentFile = new DateTime (1601, 1, 1);
+
+ void CreateNewReference ()
+ {
+ timeStamp = File.GetLastWriteTimeUtc (path);
+ if (timeStamp == NonExistentFile) {
+ Reference = null;
+ } else {
+ Reference = MetadataReference.CreateFromFile (path, MetadataReferenceProperties.Assembly);
+ }
+ }
+ }
+ }
+}
+