diff options
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem')
3 files changed, 259 insertions, 204 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/AmbienceService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/AmbienceService.cs index 27d7d7169d..794144d931 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/AmbienceService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/AmbienceService.cs @@ -432,7 +432,6 @@ namespace MonoDevelop.Ide.TypeSystem StringBuilder ret = new StringBuilder (70); StringBuilder parameterBuilder = new StringBuilder (); StringBuilder exceptions = new StringBuilder (); - exceptions.AppendLine (options.FormatHeading (GettextCatalog.GetString ("Exceptions:"))); // ret.Append ("<small>"); int paramCount = 0, exceptionCount = 0, summaryEnd = -1; @@ -509,6 +508,8 @@ namespace MonoDevelop.Ide.TypeSystem parameterBuilder.Append ("</b>"); parameterBuilder.Append (":</i> "); parameterBuilder.Append (body); + } else { + return null; } break; case "value": diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ParsedDocument.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ParsedDocument.cs index a47d916d7a..0fdb4a13cd 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ParsedDocument.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/ParsedDocument.cs @@ -272,7 +272,7 @@ namespace MonoDevelop.Ide.TypeSystem public DefaultParsedDocument (string fileName) : base (fileName) { - + Flags |= ParsedDocumentFlags.NonSerializable; } #region IUnresolvedFile implementation 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 4a935785de..783044f2b7 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs @@ -48,6 +48,7 @@ using System.Text; using ICSharpCode.NRefactory.Completion; using System.Diagnostics; using MonoDevelop.Projects.SharedAssetsProjects; +using Mono.CSharp.Nullable; namespace MonoDevelop.Ide.TypeSystem { @@ -159,7 +160,7 @@ namespace MonoDevelop.Ide.TypeSystem public static class TypeSystemService { - const string CurrentVersion = "1.1.5"; + const string CurrentVersion = "1.1.8"; static readonly List<TypeSystemParserNode> parsers; static string[] filesSkippedInParseThread = new string[0]; @@ -255,7 +256,7 @@ namespace MonoDevelop.Ide.TypeSystem if (project != null) CheckProjectOutput (project, true); - pr.Value.ReconnectAssemblyReferences (); + pr.Value.referencesConnected = false; } } @@ -269,6 +270,8 @@ namespace MonoDevelop.Ide.TypeSystem var fileName = project.GetOutputFileName (IdeApp.Workspace.ActiveConfiguration); var wrapper = GetProjectContentWrapper (project); + if (wrapper == null) + return; bool update = wrapper.UpdateTrackedOutputAssembly (fileName); if (autoUpdate && update) { wrapper.ReconnectAssemblyReferences (); @@ -372,7 +375,7 @@ namespace MonoDevelop.Ide.TypeSystem wrapper = null; } if (wrapper != null && (result.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) { - var oldFile = wrapper.Content.GetFile (fileName); + var oldFile = wrapper._content.GetFile (fileName); wrapper.UpdateContent (c => c.AddOrUpdateFiles (result.ParsedFile)); UpdateProjectCommentTasks (wrapper, result); if (oldFile != null) @@ -387,7 +390,7 @@ namespace MonoDevelop.Ide.TypeSystem continue; // Use the project context because file lookup is faster there than in the project class. var pcnt = cnt.Value; - var file = pcnt.Content.GetFile (fileName); + var file = pcnt._content.GetFile (fileName); if (file != null) { var newResult = parser.Parse (false, fileName, new StringReader (content), pcnt.Project); pcnt.UpdateContent (c => c.AddOrUpdateFiles (newResult.ParsedFile)); @@ -431,7 +434,7 @@ namespace MonoDevelop.Ide.TypeSystem var result = parser.Parse (true, fileName, content); lock (projectWrapperUpdateLock) { if (wrapper != null && (result.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) { - var oldFile = wrapper.Content.GetFile (fileName); + var oldFile = wrapper._content.GetFile (fileName); wrapper.UpdateContent (c => c.AddOrUpdateFiles (result.ParsedFile)); UpdateProjectCommentTasks (wrapper, result); if (oldFile != null) @@ -943,42 +946,22 @@ namespace MonoDevelop.Ide.TypeSystem readonly Dictionary<Type, object> extensionObjects = new Dictionary<Type, object> (); List<ProjectContentWrapper> referencedWrappers = new List<ProjectContentWrapper>(); List<UnresolvedAssemblyProxy> referencedAssemblies = new List<UnresolvedAssemblyProxy>(); - IProjectContent _content; - bool referencesConnected; - - public bool ReferencesConnected { - get { - return GetReferencesConnected (this, new HashSet<ProjectContentWrapper> ()); - } - } + internal IProjectContent _content; + internal bool referencesConnected; + /* static bool GetReferencesConnected (ProjectContentWrapper pcw, HashSet<ProjectContentWrapper> wrapper) { if (wrapper.Contains (pcw)) return true; wrapper.Add (pcw); return pcw.referencesConnected && pcw.referencedWrappers.All (w => GetReferencesConnected (w, wrapper)); - } - - public bool IsLoaded { - get { - return GetIsLoaded (this, new HashSet<ProjectContentWrapper> ()); - } - } - - static bool GetIsLoaded (ProjectContentWrapper pcw, HashSet<ProjectContentWrapper> wrapper) - { - if (wrapper.Contains (pcw)) - return true; - wrapper.Add (pcw); - return !pcw.InLoad && pcw.referencedWrappers.All (w => GetIsLoaded (w, wrapper)); - } + }*/ public IProjectContent Content { get { if (!referencesConnected) { - referencesConnected = true; - ReconnectAssemblyReferences (); + EnsureReferencesAreLoaded (); } return _content; } @@ -1050,12 +1033,14 @@ namespace MonoDevelop.Ide.TypeSystem public void RunWhenLoaded (Action<IProjectContent> act) { lock (updateContentLock) { - if (Content is LazyProjectLoader) { - if (loadActions != null) { - loadActions.Clear (); - loadActions.Add (act); + var lazyProjectLoader = _content as LazyProjectLoader; + if (loadActions != null) { + lock (loadActions) { + if (lazyProjectLoader != null && !lazyProjectLoader.ContextTask.IsCompleted) { + loadActions.Add (act); + return; + } } - return; } } act (Content); @@ -1073,29 +1058,43 @@ namespace MonoDevelop.Ide.TypeSystem continue; cleared.Add (cur); cur.compilation = null; - foreach (var project in cur.ReferencedProjects) - stack.Push (GetProjectContentWrapper (project)); + foreach (var project in cur.ReferencedProjects) { + var projectContentWrapper = GetProjectContentWrapper (project); + if (projectContentWrapper != null) + stack.Push (projectContentWrapper); + } } } readonly object updateContentLock = new object (); + void RunLoadActions () + { + if (loadActions == null) + return; + Action<IProjectContent>[] actions; + lock (loadActions) { + actions = loadActions.ToArray (); + loadActions = null; + } + foreach (var action in actions) + action (Content); + } + public void UpdateContent (Func<IProjectContent, IProjectContent> updateFunc) { + LazyProjectLoader lazyProjectLoader; lock (updateContentLock) { - var lazyProjectLoader = Content as LazyProjectLoader; + lazyProjectLoader = Content as LazyProjectLoader; if (lazyProjectLoader != null) { lazyProjectLoader.ContextTask.Wait (); - if (loadActions != null) { - var action = loadActions.FirstOrDefault (); - loadActions = null; - if (action != null) - action (Content); - } } Content = updateFunc (Content); ClearCachedCompilations (); WasChanged = true; + if (lazyProjectLoader != null && !(Content is LazyProjectLoader)) { + RunLoadActions (); + } } } @@ -1144,6 +1143,8 @@ namespace MonoDevelop.Ide.TypeSystem { lock (loadOperationLocker) { loadOperationDepth++; + if (loadOperationDepth == 1) + UpdateLoadState (); } } @@ -1153,13 +1154,15 @@ namespace MonoDevelop.Ide.TypeSystem if (loadOperationDepth > 0) { loadOperationDepth--; } + if (loadOperationDepth == 0) + UpdateLoadState (); } - OnLoad (EventArgs.Empty); } - bool inLoad; - public bool InLoad { + + bool isLoaded; + public bool IsLoaded { get { - return inLoad; + return isLoaded; } } @@ -1174,52 +1177,38 @@ namespace MonoDevelop.Ide.TypeSystem void UpdateLoadState () { - inLoad = loadOperationDepth > 0 || referencedWrappers.Any (w => w.InLoad) || referencedAssemblies.Any (a => a.InLoad); + bool wasLoaded = isLoaded; + isLoaded = loadOperationDepth == 0 && referencesConnected && !referencedAssemblies.Any (a => a.InLoad); + if (isLoaded && !wasLoaded) + OnLoad (EventArgs.Empty); } internal void RequestLoad () { - UpdateLoadState (); - if (!InLoad) - return; + BeginLoadOperation (); + EnsureReferencesAreLoaded (); CancelLoad (); src = new CancellationTokenSource (); var token = src.Token; - Task.Factory.StartNew (delegate { - var s = new Stack<ProjectContentWrapper> (); - s.Push (this); - var w = new HashSet<ProjectContentWrapper> (); - while (s.Count > 0) { - var wrapper = s.Pop (); - if (token.IsCancellationRequested) - return; - if (w.Contains (wrapper)) - continue; - w.Add (wrapper); - - foreach (var asm in wrapper.referencedAssemblies.ToArray ()) { + //Task.Factory.StartNew (delegate { + try { + foreach (var asm in referencedAssemblies.ToArray ()) { if (token.IsCancellationRequested) - return; + break; var ctxLoader = asm.CtxLoader; if (ctxLoader != null) ctxLoader.EnsureAssemblyLoaded (); } - foreach (var rw in wrapper.referencedWrappers.ToArray ()) { - if (token.IsCancellationRequested) - return; - s.Push (rw); - } + } finally { + EndLoadOperation (); } - }); + //}); } public event EventHandler Loaded; protected virtual void OnLoad (EventArgs e) { - UpdateLoadState (); - if (InLoad) - return; var handler = Loaded; if (handler != null) handler (this, e); @@ -1244,7 +1233,8 @@ namespace MonoDevelop.Ide.TypeSystem if (project == null) throw new ArgumentNullException ("project"); this.Project = project; - this.Content = new LazyProjectLoader (this); + var lazyProjectLoader = new LazyProjectLoader (this); + this.Content = lazyProjectLoader; } public IEnumerable<Project> ReferencedProjects { @@ -1263,18 +1253,29 @@ namespace MonoDevelop.Ide.TypeSystem return contextTask; } } - + object contentLock = new object (); + IProjectContent contentWithReferences; public IProjectContent Content { get { - if (References != null) - return contextTask.Result.AddAssemblyReferences (References); - return contextTask.Result; + lock (contentLock) { + if (References != null) { + return contentWithReferences ?? (contentWithReferences = contextTask.Result.AddAssemblyReferences (References)); + } + return contextTask.Result; + } } } + List<IAssemblyReference> references; public List<IAssemblyReference> References { - get; - set; + get { + return references; + } + set { + lock (contentLock) { + references = value; + } + } } public LazyProjectLoader (ProjectContentWrapper wrapper) @@ -1504,106 +1505,127 @@ namespace MonoDevelop.Ide.TypeSystem } return false; } - public void ReconnectAssemblyReferences () + + List<UnresolvedAssemblyProxy> LoadReferencedAssemblies (DotNetProject netProject) { - var netProject = Project as DotNetProject; - if (netProject == null) - return; - CancelLoad (); + var newReferencedAssemblies = new List<UnresolvedAssemblyProxy> (); try { - var contexts = new List<IAssemblyReference> (); - var nonCyclicCache = new HashSet<Project> (); - foreach (var referencedWrapper in referencedWrappers) { - referencedWrapper.Loaded -= HandleReferencedProjectInLoadChange; - } - var newReferencedWrappers = new List<ProjectContentWrapper>(); - foreach (var referencedProject in ReferencedProjects) { - ProjectContentWrapper wrapper; - if (projectContents.TryGetValue (referencedProject, out wrapper)) { - if (HasCyclicRefs (wrapper, nonCyclicCache)) - continue; - wrapper.Loaded += HandleReferencedProjectInLoadChange; - newReferencedWrappers.Add (wrapper); - contexts.Add (new UnresolvedAssemblyDecorator (wrapper)); + foreach (string file in netProject.GetReferencedAssemblies (IdeApp.IsInitialized ? IdeApp.Workspace.ActiveConfiguration : ConfigurationSelector.Default, false)) { + string fileName; + if (!Path.IsPathRooted (file)) { + fileName = Path.Combine (Path.GetDirectoryName (netProject.FileName), file); + } + else { + fileName = Path.GetFullPath (file); + } + var ctx = LoadAssemblyContext (fileName); + if (ctx != null) { + newReferencedAssemblies.Add (ctx); + ctx.Loaded += HandleReferencedProjectInLoadChange; + } + else { + LoggingService.LogWarning ("TypeSystemService: Can't load assembly context for:" + file); } } - this.referencedWrappers = newReferencedWrappers; + } + catch (Exception e) { + LoggingService.LogError ("Error while getting assembly references", e); + } + return newReferencedAssemblies; + } - UnresolvedAssemblyProxy ctx; - // Add mscorlib reference + object assemblyReconnectLock = new object(); - var config = IdeApp.Workspace != null ? netProject.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as DotNetProjectConfiguration : null; - bool noStdLib = false; - if (config != null) { - var parameters = config.CompilationParameters as DotNetConfigurationParameters; - if (parameters != null) { - noStdLib = parameters.NoStdLib; + public void EnsureReferencesAreLoaded () + { + lock (assemblyReconnectLock) { + if (referencesConnected) + return; + compilation = null; + referencesConnected = true; + var netProject = Project as DotNetProject; + if (netProject == null) + return; + try { + var contexts = new List<IAssemblyReference> (); + var nonCyclicCache = new HashSet<Project> (); + foreach (var referencedWrapper in referencedWrappers) { + referencedWrapper.Loaded -= HandleReferencedProjectInLoadChange; } - } - - if (!noStdLib && netProject.TargetRuntime != null && netProject.TargetRuntime.AssemblyContext != null) { - var corLibRef = netProject.TargetRuntime.AssemblyContext.GetAssemblyForVersion ( - typeof(object).Assembly.FullName, - null, - netProject.TargetFramework - ); - if (corLibRef != null) { - ctx = LoadAssemblyContext (corLibRef.Location); - if (ctx != null) - contexts.Add (ctx); + var newReferencedWrappers = new List<ProjectContentWrapper> (); + foreach (var referencedProject in ReferencedProjects) { + ProjectContentWrapper wrapper; + if (projectContents.TryGetValue (referencedProject, out wrapper)) { + if (HasCyclicRefs (wrapper, nonCyclicCache)) + continue; + wrapper.Loaded += HandleReferencedProjectInLoadChange; + newReferencedWrappers.Add (wrapper); + contexts.Add (new UnresolvedAssemblyDecorator (wrapper)); + } } - } - // Get the assembly references throught the project, since it may have custom references - foreach (var asm in referencedAssemblies) { - asm.Loaded += HandleReferencedProjectInLoadChange; - } - var newReferencedAssemblies = new List<UnresolvedAssemblyProxy>(); - try { - foreach (string file in netProject.GetReferencedAssemblies (IdeApp.IsInitialized ? IdeApp.Workspace.ActiveConfiguration : ConfigurationSelector.Default, false)) { - string fileName; - if (!Path.IsPathRooted (file)) { - fileName = Path.Combine (Path.GetDirectoryName (netProject.FileName), file); - } else { - fileName = Path.GetFullPath (file); + this.referencedWrappers = newReferencedWrappers; + UnresolvedAssemblyProxy ctx; + // Add mscorlib reference + var config = IdeApp.Workspace != null ? netProject.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as DotNetProjectConfiguration : null; + bool noStdLib = false; + if (config != null) { + var parameters = config.CompilationParameters as DotNetCompilerParameters; + if (parameters != null) { + noStdLib = parameters.NoStdLib; } - ctx = LoadAssemblyContext (fileName); - if (ctx != null) { - newReferencedAssemblies.Add (ctx); - ctx.Loaded += HandleReferencedProjectInLoadChange; - contexts.Add (ctx); - } else { - LoggingService.LogWarning ("TypeSystemService: Can't load assembly context for:" + file); + } + if (!noStdLib && netProject.TargetRuntime != null && netProject.TargetRuntime.AssemblyContext != null) { + var corLibRef = netProject.TargetRuntime.AssemblyContext.GetAssemblyForVersion (typeof(object).Assembly.FullName, null, netProject.TargetFramework); + if (corLibRef != null) { + ctx = LoadAssemblyContext (corLibRef.Location); + if (ctx != null) + contexts.Add (ctx); } } + // Get the assembly references throught the project, since it may have custom references + foreach (var asm in referencedAssemblies) { + asm.Loaded += HandleReferencedProjectInLoadChange; + } + var newReferencedAssemblies = LoadReferencedAssemblies (netProject); + contexts.AddRange (newReferencedAssemblies); + referencedAssemblies = newReferencedAssemblies; + bool changed = WasChanged; + var lazyProjectLoader = Content as LazyProjectLoader; + if (lazyProjectLoader != null) { + lazyProjectLoader.References = contexts; + } + else { + UpdateContent (c => c.RemoveAssemblyReferences (Content.AssemblyReferences).AddAssemblyReferences (contexts)); + } + WasChanged = changed; } catch (Exception e) { - LoggingService.LogError ("Error while getting assembly references", e); - } - referencedAssemblies = newReferencedAssemblies; - bool changed = WasChanged; - var lazyProjectLoader = Content as LazyProjectLoader; - if (lazyProjectLoader != null) { - lazyProjectLoader.References = contexts; - } else { - UpdateContent (c => c.RemoveAssemblyReferences (Content.AssemblyReferences)); - UpdateContent (c => c.AddAssemblyReferences (contexts)); - } - WasChanged = changed; - } catch (Exception e) { - if (netProject.TargetRuntime == null) { - LoggingService.LogError ("Target runtime was null: " + Project.Name); - } else if (netProject.TargetRuntime.AssemblyContext == null) { - LoggingService.LogError ("Target runtime assembly context was null: " + Project.Name); + if (netProject.TargetRuntime == null) { + LoggingService.LogError ("Target runtime was null: " + Project.Name); + } else if (netProject.TargetRuntime.AssemblyContext == null) { + LoggingService.LogError ("Target runtime assembly context was null: " + Project.Name); + } + LoggingService.LogError ("Error while reloading all references of project: " + Project.Name, e); + } finally { + UpdateLoadState (); } - LoggingService.LogError ("Error while reloading all references of project: " + Project.Name, e); - } finally { + } + } + object reconnectLock = new object(); + public void ReconnectAssemblyReferences () + { + var netProject = Project as DotNetProject; + if (netProject == null) + return; + lock (reconnectLock) { + CancelLoad (); + this.referencesConnected = false; RequestLoad (); - OnLoad (EventArgs.Empty); } } void HandleReferencedProjectInLoadChange (object sender, EventArgs e) { - OnLoad (EventArgs.Empty); + UpdateLoadState (); } internal void Unload () @@ -1643,7 +1665,6 @@ namespace MonoDevelop.Ide.TypeSystem project.FileRenamedInProject += OnFileRenamed; project.Modified += OnProjectModified; - if (dotNetProject != null) { StartFrameworkLookup (dotNetProject); } @@ -1686,7 +1707,7 @@ namespace MonoDevelop.Ide.TypeSystem foreach (ProjectFileEventInfo fargs in args) { var wrapper = projectContents [project]; var fileName = fargs.ProjectFile.Name; - var file = wrapper.Content.GetFile (fileName); + var file = wrapper._content.GetFile (fileName); if (file == null) continue; wrapper.UpdateContent (c => c.RemoveFiles (fileName)); @@ -1703,7 +1724,7 @@ namespace MonoDevelop.Ide.TypeSystem var project = (Project)sender; foreach (ProjectFileRenamedEventInfo fargs in args) { var content = projectContents [project]; - var file = content.Content.GetFile (fargs.OldName); + var file = content._content.GetFile (fargs.OldName); if (file == null) continue; content.UpdateContent (c => c.RemoveFiles (fargs.OldName)); @@ -1763,7 +1784,7 @@ namespace MonoDevelop.Ide.TypeSystem TrackFileChanges = true; } - internal static void UnloadProject (Project project) + internal static void UnloadProject (Project project, bool skipProjectSerialization = false) { if (DecLoadCount (project) != 0) return; @@ -1779,7 +1800,8 @@ namespace MonoDevelop.Ide.TypeSystem return; projectContents.Remove (project); } - StoreProjectCache (project, wrapper); + if (!skipProjectSerialization) + StoreProjectCache (project, wrapper); OnProjectUnloaded (new ProjectUnloadEventArgs (project, wrapper)); wrapper.Unload (); } @@ -1809,10 +1831,10 @@ namespace MonoDevelop.Ide.TypeSystem if (project != null) { var wrapper = LoadProject (project); if (wrapper != null) { - wrapper.ReconnectAssemblyReferences (); var files = wrapper.Project.Files.ToArray (); Task.Factory.StartNew (delegate { CheckModifiedFiles (wrapper.Project, files, wrapper); + wrapper.RequestLoad (); }); } } @@ -2020,6 +2042,11 @@ namespace MonoDevelop.Ide.TypeSystem } #endregion + + public override string ToString () + { + return string.Format ("[UnresolvedAssemblyProxy: FileName={0}]", FileName); + } } internal class LazyAssemblyLoader : IUnresolvedAssembly @@ -2242,11 +2269,13 @@ namespace MonoDevelop.Ide.TypeSystem this.cache = cache; } + IUnresolvedAssembly LoadAssembly () { var assemblyPath = cache != null ? Path.Combine (cache, "assembly.data") : null; + var assemblyTag = cache != null ? Path.Combine (cache, "assembly.tag") : null; try { - if (assemblyPath != null && File.Exists (assemblyPath)) { + if (assemblyPath != null && assemblyTag != null && File.Exists (assemblyPath) && File.Exists (assemblyTag)) { var deserializedAssembly = DeserializeObject <IUnresolvedAssembly> (assemblyPath); if (deserializedAssembly != null) { return deserializedAssembly; @@ -2268,13 +2297,7 @@ namespace MonoDevelop.Ide.TypeSystem if (cache != null) { var writeTime = File.GetLastWriteTimeUtc (fileName); SerializeObject (assemblyPath, result); - if (File.Exists (assemblyPath)) { - try { - File.SetCreationTimeUtc (assemblyPath, writeTime); - } catch (Exception e) { - LoggingService.LogError ("Can't set creation time for: " + assemblyPath, e); - } - } + SerializeObject (assemblyTag, new AssemblyTag (writeTime)); } return result; } @@ -2380,6 +2403,8 @@ namespace MonoDevelop.Ide.TypeSystem if (project == null) throw new ArgumentNullException ("project"); var content = GetProjectContentWrapper (project); + if (content == null) + return null; return content.Content; } @@ -2388,6 +2413,8 @@ namespace MonoDevelop.Ide.TypeSystem if (project == null) throw new ArgumentNullException ("project"); var content = GetProjectContentWrapper (project); + if (content == null) + return null; return content.Compilation; } @@ -2532,7 +2559,12 @@ namespace MonoDevelop.Ide.TypeSystem ProjectContentWrapper content; if (projectContents.TryGetValue (project, out content)) return content; - return new ProjectContentWrapper (project); + // in case of outdated projects try to get the most recent project wrapper. + foreach (var cnt in projectContents) { + if (cnt.Key.FileName == project.FileName) + return cnt.Value; + } + return null; } public static IProjectContent GetContext (FilePath file, string mimeType, string text) @@ -2569,7 +2601,7 @@ namespace MonoDevelop.Ide.TypeSystem } class InternalProgressMonitor - : NullProgressMonitor + : ProgressMonitor { public InternalProgressMonitor () { @@ -2582,9 +2614,9 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static IProgressMonitor GetParseProgressMonitor () + internal static ProgressMonitor GetParseProgressMonitor () { - var mon = ParseProgressMonitorFactory != null ? ParseProgressMonitorFactory.CreateProgressMonitor () : new NullProgressMonitor (); + var mon = ParseProgressMonitorFactory != null ? ParseProgressMonitorFactory.CreateProgressMonitor () : new ProgressMonitor (); return new AggregatedProgressMonitor (mon, new InternalProgressMonitor ()); } @@ -2596,7 +2628,7 @@ namespace MonoDevelop.Ide.TypeSystem public ProjectContentWrapper Context; public IEnumerable<ProjectFile> FileList; // public Action<string, IProgressMonitor> ParseCallback; - public void Run (IProgressMonitor monitor, CancellationToken token) + public void Run (ProgressMonitor monitor, CancellationToken token) { TypeSystemParserNode node = null; TypeSystemParser parser = null; @@ -2635,7 +2667,7 @@ namespace MonoDevelop.Ide.TypeSystem tags.UpdateTags (Context.Project, parsedDocument.FileName, parsedDocument.TagComments); if (token.IsCancellationRequested) return; - parsedFiles.Add (Tuple.Create (parsedDocument, Context.Content.GetFile (fileName))); + parsedFiles.Add (Tuple.Create (parsedDocument, Context._content.GetFile (fileName))); } Context.UpdateContent (c => c.AddOrUpdateFiles (parsedFiles.Select (p => p.Item1.ParsedFile))); foreach (var file in parsedFiles) { @@ -2643,11 +2675,12 @@ namespace MonoDevelop.Ide.TypeSystem return; if (file.Item2 != null) Context.InformFileRemoved (new ParsedFileEventArgs (file.Item2)); - Context.InformFileAdded (new ParsedFileEventArgs (file.Item1.ParsedFile)); + var parsedDocument = file.Item1; + if ((parsedDocument.Flags & ParsedDocumentFlags.NonSerializable) != ParsedDocumentFlags.NonSerializable) + Context.InformFileAdded (new ParsedFileEventArgs (parsedDocument.ParsedFile)); } } finally { - if (!token.IsCancellationRequested) - Context.EndLoadOperation (); + Context.EndLoadOperation (); } } } @@ -2781,28 +2814,31 @@ namespace MonoDevelop.Ide.TypeSystem static bool IsFileModified (ProjectFile file, IUnresolvedFile parsedFile) { - if (parsedFile == null) + if (parsedFile == null || !parsedFile.LastWriteTime.HasValue) return true; try { - return File.GetLastWriteTimeUtc (file.FilePath) > parsedFile.LastWriteTime; + return File.GetLastWriteTimeUtc (file.FilePath) != parsedFile.LastWriteTime; } catch (Exception) { - return false; + return true; } } static void CheckModifiedFiles (Project project, ProjectFile[] projectFiles, ProjectContentWrapper content, CancellationToken token = default (CancellationToken)) { - if (token.IsCancellationRequested) + if (token.IsCancellationRequested) { return; + } +// Console.WriteLine ("add modified file check for :" + project.Name); content.RunWhenLoaded (delegate(IProjectContent cnt) { try { +// Console.WriteLine ("check for " + project.Name); content.BeginLoadOperation (); var modifiedFiles = new List<ProjectFile> (); var oldFileNewFile = new List<Tuple<ProjectFile, IUnresolvedFile>> (); - foreach (var file in projectFiles) { - if (token.IsCancellationRequested) + if (token.IsCancellationRequested) { return; + } if (file.BuildAction == null) continue; // if the file is already inside the content a parser exists for it, if not check if it can be parsed. @@ -2827,8 +2863,9 @@ namespace MonoDevelop.Ide.TypeSystem // check if file needs to be removed from project content foreach (var file in cnt.Files) { - if (token.IsCancellationRequested) + if (token.IsCancellationRequested) { return; + } if (project.GetProjectFile (file.FileName) == null) { content.UpdateContent (c => c.RemoveFiles (file.FileName)); content.InformFileRemoved (new ParsedFileEventArgs (file)); @@ -2836,37 +2873,54 @@ namespace MonoDevelop.Ide.TypeSystem tags.RemoveFile (project, file.FileName); } } - if (token.IsCancellationRequested) + if (token.IsCancellationRequested) { return; - if (modifiedFiles.Count > 0) + } + if (modifiedFiles.Count > 0) { QueueParseJob (content, modifiedFiles); + WaitForParseJob (); + } } catch (Exception e) { LoggingService.LogError ("Exception in check modified files.", e); } finally { content.EndLoadOperation (); } - }); } + /// <summary> + /// Used to store meta data information about the assembly. + /// </summary> + [Serializable] + class AssemblyTag + { + public DateTime LastWriteTimeUTC { get; set; } + + public AssemblyTag (DateTime lastWriteTimeUTC) + { + this.LastWriteTimeUTC = lastWriteTimeUTC; + } + } + static void CheckModifiedFile (UnresolvedAssemblyProxy context) { try { string cache = GetCacheDirectory (context.FileName); if (cache == null) return; - var assemblyDataDirectory = Path.Combine (cache, "assembly.data"); + var assemblyDataDirectory = Path.Combine (cache, "assembly.tag"); var writeTime = File.GetLastWriteTimeUtc (context.FileName); - var cacheTime = File.Exists (assemblyDataDirectory) ? File.GetCreationTimeUtc (assemblyDataDirectory) : writeTime; - if (writeTime != cacheTime) { + var cacheTime = File.Exists (assemblyDataDirectory) ? DeserializeObject<AssemblyTag> (assemblyDataDirectory) : new AssemblyTag (writeTime); + if (writeTime != cacheTime.LastWriteTimeUTC) { cache = GetCacheDirectory (context.FileName); if (cache != null) { - context.CtxLoader = new LazyAssemblyLoader (context.FileName, cache); try { - // File is reloaded by the lazy loader + // Files will be reloaded by the lazy loader File.Delete (assemblyDataDirectory); + File.Delete (Path.Combine (cache, "assembly.data")); } catch { } + context.CtxLoader = new LazyAssemblyLoader (context.FileName, cache); } } } catch (Exception e) { @@ -2899,7 +2953,7 @@ namespace MonoDevelop.Ide.TypeSystem static void ConsumeParsingQueue () { int pending = 0; - IProgressMonitor monitor = null; + ProgressMonitor monitor = null; var token = loadCancellationSource.Token; StartParseOperation (); try { |