Browse Source
Fixed ArgumentNullException in TaskListPad / ParserService. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5239 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61pull/1/head
19 changed files with 196 additions and 1057 deletions
@ -1,913 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Editor; |
|
||||||
using System; |
|
||||||
using System.Collections; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.IO; |
|
||||||
using System.Text; |
|
||||||
using System.Threading; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; |
|
||||||
using ICSharpCode.SharpDevelop.Dom; |
|
||||||
using ICSharpCode.SharpDevelop.Dom.Refactoring; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
using RegistryContentPair = System.Collections.Generic.KeyValuePair<ICSharpCode.SharpDevelop.Dom.ProjectContentRegistry, ICSharpCode.SharpDevelop.Dom.IProjectContent>; |
|
||||||
|
|
||||||
namespace ICSharpCode.SharpDevelop |
|
||||||
{ |
|
||||||
public static class OldParserService |
|
||||||
{ |
|
||||||
static IList<ParserDescriptor> parser; |
|
||||||
static IList<ProjectContentRegistryDescriptor> registries; |
|
||||||
|
|
||||||
static Dictionary<IProject, IProjectContent> projectContents = new Dictionary<IProject, IProjectContent>(); |
|
||||||
static Dictionary<string, ParseInformation> parsings = new Dictionary<string, ParseInformation>(StringComparer.OrdinalIgnoreCase); |
|
||||||
static ProjectContentRegistry defaultProjectContentRegistry = new ProjectContentRegistry(); |
|
||||||
|
|
||||||
static string domPersistencePath; |
|
||||||
|
|
||||||
internal static void InitializeParserService() |
|
||||||
{ |
|
||||||
if (parser == null) { |
|
||||||
parser = AddInTree.BuildItems<ParserDescriptor>("/Workspace/Parser", null, false); |
|
||||||
registries = AddInTree.BuildItems<ProjectContentRegistryDescriptor>("/Workspace/ProjectContentRegistry", null, false); |
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(domPersistencePath)) { |
|
||||||
Directory.CreateDirectory(domPersistencePath); |
|
||||||
defaultProjectContentRegistry.ActivatePersistence(domPersistencePath); |
|
||||||
} |
|
||||||
ProjectService.SolutionClosed += ProjectServiceSolutionClosed; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets the cache directory used for DOM persistence.
|
|
||||||
/// </summary>
|
|
||||||
public static string DomPersistencePath { |
|
||||||
get { |
|
||||||
return domPersistencePath; |
|
||||||
} |
|
||||||
set { |
|
||||||
if (parser != null) |
|
||||||
throw new InvalidOperationException("Cannot set DomPersistencePath after ParserService was initialized"); |
|
||||||
domPersistencePath = value; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static ProjectContentRegistry DefaultProjectContentRegistry { |
|
||||||
get { |
|
||||||
return defaultProjectContentRegistry; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static IProjectContent CurrentProjectContent { |
|
||||||
[DebuggerStepThrough] |
|
||||||
get { |
|
||||||
if (ProjectService.CurrentProject == null || !projectContents.ContainsKey(ProjectService.CurrentProject)) { |
|
||||||
return DefaultProjectContent; |
|
||||||
} |
|
||||||
return projectContents[ProjectService.CurrentProject]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of project contents of all open projects. Does not include assembly project contents.
|
|
||||||
/// </summary>
|
|
||||||
public static IEnumerable<IProjectContent> AllProjectContents { |
|
||||||
get { |
|
||||||
return projectContents.Values; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void ProjectServiceSolutionClosed(object sender, EventArgs e) |
|
||||||
{ |
|
||||||
abortLoadSolutionProjectsThread = true; |
|
||||||
|
|
||||||
lock (reParse1) { // clear queue of reparse thread
|
|
||||||
reParse1.Clear(); |
|
||||||
reParse2.Clear(); |
|
||||||
} |
|
||||||
lock (projectContents) { |
|
||||||
foreach (IProjectContent content in projectContents.Values) { |
|
||||||
content.Dispose(); |
|
||||||
} |
|
||||||
projectContents.Clear(); |
|
||||||
} |
|
||||||
lock (parsings) { |
|
||||||
parsings.Clear(); |
|
||||||
} |
|
||||||
lock (parseQueue) { |
|
||||||
parseQueue.Clear(); |
|
||||||
} |
|
||||||
lastUpdateHash.Clear(); |
|
||||||
} |
|
||||||
|
|
||||||
static Thread loadSolutionProjectsThread; |
|
||||||
static bool abortLoadSolutionProjectsThread; |
|
||||||
|
|
||||||
// do not use an event for this because a solution might be loaded before ParserService
|
|
||||||
// is initialized
|
|
||||||
internal static void OnSolutionLoaded() |
|
||||||
{ |
|
||||||
if (loadSolutionProjectsThread != null) { |
|
||||||
if (!abortLoadSolutionProjectsThread) |
|
||||||
throw new InvalidOperationException("Cannot open new solution without closing old solution!"); |
|
||||||
if (!loadSolutionProjectsThread.Join(50)) { |
|
||||||
// loadSolutionProjects might be waiting for main thread, so give it
|
|
||||||
// a chance to complete safethread calls by putting this method at
|
|
||||||
// the end of the invoking queue
|
|
||||||
WorkbenchSingleton.SafeThreadAsyncCall(OnSolutionLoaded); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
loadSolutionProjectsThread = new Thread(new ThreadStart(LoadSolutionProjects)); |
|
||||||
loadSolutionProjectsThread.Name = "loadSolutionProjects"; |
|
||||||
loadSolutionProjectsThread.Priority = ThreadPriority.BelowNormal; |
|
||||||
loadSolutionProjectsThread.IsBackground = true; |
|
||||||
loadSolutionProjectsThread.Start(); |
|
||||||
} |
|
||||||
|
|
||||||
public static bool LoadSolutionProjectsThreadRunning { |
|
||||||
get { |
|
||||||
return loadSolutionProjectsThread != null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void LoadSolutionProjects() |
|
||||||
{ |
|
||||||
try { |
|
||||||
abortLoadSolutionProjectsThread = false; |
|
||||||
LoggingService.Info("Start LoadSolutionProjects thread"); |
|
||||||
LoadSolutionProjectsInternal(); |
|
||||||
} finally { |
|
||||||
LoggingService.Info("LoadSolutionProjects thread ended"); |
|
||||||
loadSolutionProjectsThread = null; |
|
||||||
OnLoadSolutionProjectsThreadEnded(EventArgs.Empty); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void LoadSolutionProjectsInternal() |
|
||||||
{ |
|
||||||
IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); |
|
||||||
List<ParseProjectContent> createdContents = new List<ParseProjectContent>(); |
|
||||||
foreach (IProject project in ProjectService.OpenSolution.Projects) { |
|
||||||
try { |
|
||||||
ParseProjectContent newContent = project.CreateProjectContent(); |
|
||||||
if (newContent != null) { |
|
||||||
lock (projectContents) { |
|
||||||
projectContents[project] = newContent; |
|
||||||
} |
|
||||||
createdContents.Add(newContent); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e, "Error while retrieving project contents from " + project); |
|
||||||
} |
|
||||||
} |
|
||||||
WorkbenchSingleton.SafeThreadAsyncCall(ProjectService.ParserServiceCreatedProjectContents); |
|
||||||
try { |
|
||||||
int workAmount = 0; |
|
||||||
// multiply Count with 2 so that the progress bar is only at 50% when references are done
|
|
||||||
progressMonitor.BeginTask("Loading references...", createdContents.Count * 2, false); |
|
||||||
|
|
||||||
for (int i = 0; i < createdContents.Count; i++) { |
|
||||||
if (abortLoadSolutionProjectsThread) return; |
|
||||||
ParseProjectContent newContent = createdContents[i]; |
|
||||||
progressMonitor.WorkDone = i; |
|
||||||
try { |
|
||||||
newContent.Initialize1(progressMonitor); |
|
||||||
workAmount += newContent.GetInitializationWorkAmount(); |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e, "Error while initializing project references:" + newContent); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// multiply workamount with two and start at workAmount so that the progress bar continues
|
|
||||||
// from 50% towards 100%.
|
|
||||||
progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount * 2, false); |
|
||||||
progressMonitor.WorkDone = workAmount; |
|
||||||
foreach (ParseProjectContent newContent in createdContents) { |
|
||||||
if (abortLoadSolutionProjectsThread) return; |
|
||||||
try { |
|
||||||
newContent.Initialize2(progressMonitor); |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e, "Error while initializing project contents:" + newContent); |
|
||||||
} |
|
||||||
} |
|
||||||
} finally { |
|
||||||
progressMonitor.Done(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void InitAddedProject(object state) |
|
||||||
{ |
|
||||||
ParseProjectContent newContent = (ParseProjectContent)state; |
|
||||||
IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); |
|
||||||
newContent.Initialize1(progressMonitor); |
|
||||||
progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", newContent.GetInitializationWorkAmount(), false); |
|
||||||
newContent.Initialize2(progressMonitor); |
|
||||||
progressMonitor.Done(); |
|
||||||
} |
|
||||||
|
|
||||||
#region Reparse projects
|
|
||||||
// queue of projects waiting to reparse references
|
|
||||||
static Queue<ParseProjectContent> reParse1 = new Queue<ParseProjectContent>(); |
|
||||||
|
|
||||||
// queue of projects waiting to reparse code
|
|
||||||
static Queue<ParseProjectContent> reParse2 = new Queue<ParseProjectContent>(); |
|
||||||
static Thread reParseThread; |
|
||||||
|
|
||||||
static void ReparseProjects() |
|
||||||
{ |
|
||||||
LoggingService.Info("reParse thread started"); |
|
||||||
Thread.Sleep(100); // enable main thread to fill the queues completely
|
|
||||||
try { |
|
||||||
ReparseProjectsInternal(); |
|
||||||
} catch (Exception ex) { |
|
||||||
MessageService.ShowException(ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void ReparseProjectsInternal() |
|
||||||
{ |
|
||||||
bool parsing = false; |
|
||||||
ParseProjectContent job; |
|
||||||
IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); |
|
||||||
|
|
||||||
while (true) { |
|
||||||
// get next job
|
|
||||||
lock (reParse1) { |
|
||||||
if (reParse1.Count > 0) { |
|
||||||
if (parsing) { |
|
||||||
progressMonitor.Done(); |
|
||||||
} |
|
||||||
parsing = false; |
|
||||||
job = reParse1.Dequeue(); |
|
||||||
} else if (reParse2.Count > 0) { |
|
||||||
if (!parsing) { |
|
||||||
int workAmount = 0; |
|
||||||
foreach (ParseProjectContent ppc in reParse2) { |
|
||||||
workAmount += ppc.GetInitializationWorkAmount(); |
|
||||||
} |
|
||||||
progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount, false); |
|
||||||
} |
|
||||||
parsing = true; |
|
||||||
job = reParse2.Dequeue(); |
|
||||||
} else { |
|
||||||
// all jobs done
|
|
||||||
reParseThread = null; |
|
||||||
if (parsing) { |
|
||||||
progressMonitor.Done(); |
|
||||||
} |
|
||||||
LoggingService.Info("reParse thread finished all jobs"); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// execute job
|
|
||||||
if (parsing) { |
|
||||||
LoggingService.Info("reparsing code for " + job.Project); |
|
||||||
job.ReInitialize2(progressMonitor); |
|
||||||
} else { |
|
||||||
LoggingService.Debug("reloading references for " + job.Project); |
|
||||||
job.ReInitialize1(progressMonitor); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void Reparse(IProject project, bool initReferences, bool parseCode) |
|
||||||
{ |
|
||||||
ParseProjectContent pc = GetProjectContent(project) as ParseProjectContent; |
|
||||||
if (pc != null) { |
|
||||||
lock (reParse1) { |
|
||||||
if (initReferences && !reParse1.Contains(pc)) { |
|
||||||
LoggingService.Debug("Enqueue for reinitializing references: " + project); |
|
||||||
reParse1.Enqueue(pc); |
|
||||||
} |
|
||||||
if (parseCode && !reParse2.Contains(pc)) { |
|
||||||
LoggingService.Debug("Enqueue for reparsing code: " + project); |
|
||||||
reParse2.Enqueue(pc); |
|
||||||
} |
|
||||||
if (reParseThread == null) { |
|
||||||
LoggingService.Info("Starting reParse thread"); |
|
||||||
reParseThread = new Thread(new ThreadStart(ReparseProjects)); |
|
||||||
reParseThread.Name = "reParse"; |
|
||||||
reParseThread.Priority = ThreadPriority.BelowNormal; |
|
||||||
reParseThread.IsBackground = true; |
|
||||||
reParseThread.Start(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <remarks>Can return null.</remarks>
|
|
||||||
internal static IProjectContent CreateProjectContentForAddedProject(IProject project) |
|
||||||
{ |
|
||||||
lock (projectContents) { |
|
||||||
ParseProjectContent newContent = project.CreateProjectContent(); |
|
||||||
if (newContent != null) { |
|
||||||
projectContents[project] = newContent; |
|
||||||
ThreadPool.QueueUserWorkItem(InitAddedProject, newContent); |
|
||||||
} |
|
||||||
return newContent; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal static void RemoveProjectContentForRemovedProject(IProject project) |
|
||||||
{ |
|
||||||
lock (projectContents) { |
|
||||||
projectContents.Remove(project); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static IProjectContent GetProjectContent(IProject project) |
|
||||||
{ |
|
||||||
lock (projectContents) { |
|
||||||
if (projectContents.ContainsKey(project)) { |
|
||||||
return projectContents[project]; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
static Queue<KeyValuePair<string, ITextBuffer>> parseQueue = new Queue<KeyValuePair<string, ITextBuffer>>(); |
|
||||||
|
|
||||||
static void ParseQueue() |
|
||||||
{ |
|
||||||
while (true) { |
|
||||||
KeyValuePair<string, ITextBuffer> entry; |
|
||||||
lock (parseQueue) { |
|
||||||
if (parseQueue.Count == 0) |
|
||||||
return; |
|
||||||
entry = parseQueue.Dequeue(); |
|
||||||
} |
|
||||||
ParseFile(entry.Key, entry.Value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void EnqueueForParsing(string fileName) |
|
||||||
{ |
|
||||||
EnqueueForParsing(fileName, GetParseableFileContent(fileName)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void EnqueueForParsing(string fileName, ITextBuffer fileContent) |
|
||||||
{ |
|
||||||
fileContent = fileContent.CreateSnapshot(); |
|
||||||
lock (parseQueue) { |
|
||||||
parseQueue.Enqueue(new KeyValuePair<string, ITextBuffer>(fileName, fileContent)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void StartParserThread() |
|
||||||
{ |
|
||||||
abortParserUpdateThread = false; |
|
||||||
Thread parserThread = new Thread(new ThreadStart(ParserUpdateThread)); |
|
||||||
parserThread.Name = "parser"; |
|
||||||
parserThread.Priority = ThreadPriority.BelowNormal; |
|
||||||
parserThread.IsBackground = true; |
|
||||||
parserThread.Start(); |
|
||||||
} |
|
||||||
|
|
||||||
public static void StopParserThread() |
|
||||||
{ |
|
||||||
abortParserUpdateThread = true; |
|
||||||
} |
|
||||||
|
|
||||||
static volatile bool abortParserUpdateThread = false; |
|
||||||
|
|
||||||
static Dictionary<string, int> lastUpdateHash = new Dictionary<string, int>(); |
|
||||||
|
|
||||||
static void ParserUpdateThread() |
|
||||||
{ |
|
||||||
LoggingService.Info("ParserUpdateThread started"); |
|
||||||
Thread.Sleep(750); |
|
||||||
|
|
||||||
// preload mscorlib, we're going to need it probably
|
|
||||||
IProjectContent dummyVar = defaultProjectContentRegistry.Mscorlib; |
|
||||||
|
|
||||||
while (!abortParserUpdateThread) { |
|
||||||
try { |
|
||||||
ParseQueue(); |
|
||||||
ParserUpdateStep(); |
|
||||||
} catch (Exception e) { |
|
||||||
ICSharpCode.Core.MessageService.ShowException(e); |
|
||||||
|
|
||||||
// don't fire an exception every 2 seconds at the user, give him at least
|
|
||||||
// time to read the first :-)
|
|
||||||
Thread.Sleep(10000); |
|
||||||
} |
|
||||||
Thread.Sleep(2000); |
|
||||||
} |
|
||||||
LoggingService.Info("ParserUpdateThread stopped"); |
|
||||||
} |
|
||||||
|
|
||||||
public static void ParseCurrentViewContent() |
|
||||||
{ |
|
||||||
ParserUpdateStep(); |
|
||||||
} |
|
||||||
|
|
||||||
static void ParserUpdateStep() |
|
||||||
{ |
|
||||||
IViewContent activeViewContent = null; |
|
||||||
string fileName = null; |
|
||||||
bool isUntitled = false; |
|
||||||
try { |
|
||||||
WorkbenchSingleton.SafeThreadCall( |
|
||||||
delegate { |
|
||||||
try { |
|
||||||
activeViewContent = WorkbenchSingleton.Workbench.ActiveViewContent; |
|
||||||
if (activeViewContent != null && activeViewContent.PrimaryFile != null) { |
|
||||||
fileName = activeViewContent.PrimaryFileName; |
|
||||||
isUntitled = activeViewContent.PrimaryFile.IsUntitled; |
|
||||||
} |
|
||||||
} catch (Exception ex) { |
|
||||||
MessageService.ShowError(ex.ToString()); |
|
||||||
} |
|
||||||
}); |
|
||||||
} catch (InvalidOperationException ex) { // includes ObjectDisposedException
|
|
||||||
// maybe workbench has been disposed while waiting for the SafeThreadCall
|
|
||||||
// can occur after workbench unload or after aborting SharpDevelop with
|
|
||||||
// Application.Exit()
|
|
||||||
LoggingService.Warn("InvalidOperationException while trying to invoke GetActiveViewContent() " + ex); |
|
||||||
return; // abort this thread
|
|
||||||
} |
|
||||||
IEditable editable = activeViewContent as IEditable; |
|
||||||
if (editable != null) { |
|
||||||
if (!(fileName == null || fileName.Length == 0)) { |
|
||||||
ParseInformation parseInformation = null; |
|
||||||
bool updated = false; |
|
||||||
ITextBuffer fileContent = editable.CreateSnapshot(); |
|
||||||
if (fileContent == null) return; |
|
||||||
parseInformation = ParseFile(fileName, fileContent, !isUntitled); |
|
||||||
updated = true; |
|
||||||
if (updated) { |
|
||||||
if (parseInformation != null && editable is IParseInformationListener) { |
|
||||||
((IParseInformationListener)editable).ParseInformationUpdated(parseInformation); |
|
||||||
} |
|
||||||
} |
|
||||||
OnParserUpdateStepFinished(new ParserUpdateStepEventArgs(fileName, fileContent, updated, parseInformation)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void ParseViewContent(IViewContent viewContent) |
|
||||||
{ |
|
||||||
ITextBuffer text = ((IEditable)viewContent).CreateSnapshot(); |
|
||||||
ParseInformation parseInformation = ParseFile(viewContent.PrimaryFileName, |
|
||||||
text, !viewContent.PrimaryFile.IsUntitled); |
|
||||||
if (parseInformation != null && viewContent is IParseInformationListener) { |
|
||||||
((IParseInformationListener)viewContent).ParseInformationUpdated(parseInformation); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>This event is called every two seconds. It is called directly after the parser has updated the
|
|
||||||
/// project content and it is called after the parser noticed that there is nothing to update.</para>
|
|
||||||
/// <para><b>WARNING: This event is called on the parser thread - You need to use Invoke if you do
|
|
||||||
/// anything in your event handler that could touch the GUI.</b></para>
|
|
||||||
/// </summary>
|
|
||||||
public static event ParserUpdateStepEventHandler ParserUpdateStepFinished; |
|
||||||
|
|
||||||
static void OnParserUpdateStepFinished(ParserUpdateStepEventArgs e) |
|
||||||
{ |
|
||||||
if (ParserUpdateStepFinished != null) { |
|
||||||
ParserUpdateStepFinished(typeof(ParserService), e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static ParseInformation ParseFile(string fileName) |
|
||||||
{ |
|
||||||
return ParseFile(fileName, null); |
|
||||||
} |
|
||||||
|
|
||||||
public static ParseInformation ParseFile(string fileName, ITextBuffer fileContent) |
|
||||||
{ |
|
||||||
return ParseFile(fileName, fileContent, true); |
|
||||||
} |
|
||||||
|
|
||||||
static IProjectContent GetProjectContent(string fileName) |
|
||||||
{ |
|
||||||
lock (projectContents) { |
|
||||||
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) { |
|
||||||
if (projectContent.Key.IsFileInProject(fileName)) { |
|
||||||
return projectContent.Value; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
static DefaultProjectContent defaultProjectContent; |
|
||||||
|
|
||||||
public static IProjectContent DefaultProjectContent { |
|
||||||
get { |
|
||||||
if (defaultProjectContent == null) { |
|
||||||
lock (projectContents) { |
|
||||||
if (defaultProjectContent == null) { |
|
||||||
CreateDefaultProjectContent(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return defaultProjectContent; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void CreateDefaultProjectContent() |
|
||||||
{ |
|
||||||
LoggingService.Info("Creating default project content"); |
|
||||||
//LoggingService.Debug("Stacktrace is:\n" + Environment.StackTrace);
|
|
||||||
defaultProjectContent = new DefaultProjectContent(); |
|
||||||
defaultProjectContent.AddReferencedContent(defaultProjectContentRegistry.Mscorlib); |
|
||||||
Thread t = new Thread(new ThreadStart(CreateDefaultProjectContentReferences)); |
|
||||||
t.IsBackground = true; |
|
||||||
t.Priority = ThreadPriority.BelowNormal; |
|
||||||
t.Name = "CreateDefaultPC"; |
|
||||||
t.Start(); |
|
||||||
} |
|
||||||
|
|
||||||
static void CreateDefaultProjectContentReferences() |
|
||||||
{ |
|
||||||
IList<string> defaultReferences = AddInTree.BuildItems<string>("/SharpDevelop/Services/ParserService/SingleFileGacReferences", null, false); |
|
||||||
foreach (string defaultReference in defaultReferences) { |
|
||||||
ReferenceProjectItem item = new ReferenceProjectItem(null, defaultReference); |
|
||||||
defaultProjectContent.AddReferencedContent(ParserService.GetProjectContentForReference(item)); |
|
||||||
} |
|
||||||
if (WorkbenchSingleton.Workbench != null) { |
|
||||||
WorkbenchSingleton.Workbench.ActiveViewContentChanged += delegate { |
|
||||||
if (WorkbenchSingleton.Workbench.ActiveViewContent != null) { |
|
||||||
string file = WorkbenchSingleton.Workbench.ActiveViewContent.PrimaryFileName; |
|
||||||
if (file != null) { |
|
||||||
IParser parser = GetParser(file); |
|
||||||
if (parser != null && parser.Language != null) { |
|
||||||
defaultProjectContent.Language = parser.Language; |
|
||||||
defaultProjectContent.DefaultImports = parser.Language.CreateDefaultImports(defaultProjectContent); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static ParseInformation ParseFile(string fileName, ITextBuffer fileContent, bool updateCommentTags) |
|
||||||
{ |
|
||||||
return ParseFile(null, fileName, fileContent, updateCommentTags); |
|
||||||
} |
|
||||||
|
|
||||||
public static ParseInformation ParseFile(IProjectContent fileProjectContent, string fileName, ITextBuffer fileContent, bool updateCommentTags) |
|
||||||
{ |
|
||||||
if (fileName == null) throw new ArgumentNullException("fileName"); |
|
||||||
|
|
||||||
IParser parser = GetParser(fileName); |
|
||||||
if (parser == null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
ICompilationUnit parserOutput = null; |
|
||||||
|
|
||||||
try { |
|
||||||
if (fileProjectContent == null) { |
|
||||||
// GetProjectContent is expensive because it compares all file names, so
|
|
||||||
// we accept the project content as optional parameter.
|
|
||||||
fileProjectContent = GetProjectContent(fileName); |
|
||||||
if (fileProjectContent == null) { |
|
||||||
fileProjectContent = DefaultProjectContent; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (fileContent == null) { |
|
||||||
if (!File.Exists(fileName)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
fileContent = GetParseableFileContent(fileName); |
|
||||||
} |
|
||||||
parserOutput = parser.Parse(fileProjectContent, fileName, fileContent); |
|
||||||
parserOutput.Freeze(); |
|
||||||
|
|
||||||
ParseInformation parseInformation; |
|
||||||
lock (parsings) { |
|
||||||
if (!parsings.TryGetValue(fileName, out parseInformation)) { |
|
||||||
parsings[fileName] = parseInformation = new ParseInformation(); |
|
||||||
} |
|
||||||
} |
|
||||||
ICompilationUnit oldUnit = parseInformation.MostRecentCompilationUnit; |
|
||||||
fileProjectContent.UpdateCompilationUnit(oldUnit, parserOutput, fileName); |
|
||||||
parseInformation.SetCompilationUnit(parserOutput); |
|
||||||
if (updateCommentTags) { |
|
||||||
TaskService.UpdateCommentTags(fileName, parserOutput.TagComments); |
|
||||||
} |
|
||||||
try { |
|
||||||
OnParseInformationUpdated(new ParseInformationEventArgs(fileName, fileProjectContent, oldUnit, parserOutput)); |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e); |
|
||||||
} |
|
||||||
return parseInformation; |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e, "Error parsing " + fileName); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content of the file using encoding auto-detection (or DefaultFileEncoding, if that fails).
|
|
||||||
/// If the file is already open, gets the text in the opened view content.
|
|
||||||
/// </summary>
|
|
||||||
public static ITextBuffer GetParseableFileContent(string fileName) |
|
||||||
{ |
|
||||||
IViewContent viewContent = FileService.GetOpenFile(fileName); |
|
||||||
IEditable editable = viewContent as IEditable; |
|
||||||
if (editable != null) { |
|
||||||
return editable.CreateSnapshot(); |
|
||||||
} |
|
||||||
//ITextBuffer res = project.GetParseableFileContent(fileName);
|
|
||||||
//if (res != null)
|
|
||||||
// return res;
|
|
||||||
|
|
||||||
OpenedFile file = FileService.GetOpenedFile(fileName); |
|
||||||
if (file != null) { |
|
||||||
IFileDocumentProvider p = file.CurrentView as IFileDocumentProvider; |
|
||||||
if (p != null) { |
|
||||||
IDocument document = p.GetDocumentForFile(file); |
|
||||||
if (document != null) { |
|
||||||
return document.CreateSnapshot(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
using(Stream s = file.OpenRead()) { |
|
||||||
// load file
|
|
||||||
Encoding encoding = DefaultFileEncoding; |
|
||||||
return new StringTextBuffer(ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(s, ref encoding)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// load file
|
|
||||||
return new StringTextBuffer(ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(fileName, DefaultFileEncoding)); |
|
||||||
} |
|
||||||
|
|
||||||
public static Encoding DefaultFileEncoding { |
|
||||||
get { |
|
||||||
return DefaultEditor.Gui.Editor.SharpDevelopTextEditorProperties.Instance.Encoding; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static ParseInformation GetParseInformation(string fileName) |
|
||||||
{ |
|
||||||
if (fileName == null || fileName.Length == 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
ParseInformation parseInfo; |
|
||||||
lock (parsings) { |
|
||||||
if (parsings.TryGetValue(fileName, out parseInfo)) |
|
||||||
return parseInfo; |
|
||||||
} |
|
||||||
return ParseFile(fileName); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers a compilation unit in the parser service.
|
|
||||||
/// Does not fire the OnParseInformationUpdated event, please use this for unit tests only!
|
|
||||||
/// </summary>
|
|
||||||
public static ParseInformation RegisterParseInformation(string fileName, ICompilationUnit cu) |
|
||||||
{ |
|
||||||
ParseInformation parseInformation; |
|
||||||
lock (parsings) { |
|
||||||
if (!parsings.TryGetValue(fileName, out parseInformation)) { |
|
||||||
parsings[fileName] = parseInformation = new ParseInformation(); |
|
||||||
} |
|
||||||
} |
|
||||||
parseInformation.SetCompilationUnit(cu); |
|
||||||
return parseInformation; |
|
||||||
} |
|
||||||
|
|
||||||
public static void ClearParseInformation(string fileName) |
|
||||||
{ |
|
||||||
if (fileName == null || fileName.Length == 0) { |
|
||||||
return; |
|
||||||
} |
|
||||||
LoggingService.Info("ClearParseInformation: " + fileName); |
|
||||||
ParseInformation parseInfo; |
|
||||||
lock (parsings) { |
|
||||||
if (parsings.TryGetValue(fileName, out parseInfo)) |
|
||||||
parsings.Remove(fileName); |
|
||||||
else |
|
||||||
return; |
|
||||||
} |
|
||||||
ICompilationUnit oldUnit = parseInfo.MostRecentCompilationUnit; |
|
||||||
if (oldUnit != null) { |
|
||||||
IProjectContent pc = parseInfo.MostRecentCompilationUnit.ProjectContent; |
|
||||||
pc.RemoveCompilationUnit(oldUnit); |
|
||||||
try { |
|
||||||
OnParseInformationUpdated(new ParseInformationEventArgs(fileName, pc, oldUnit, null)); |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static IExpressionFinder GetExpressionFinder(string fileName) |
|
||||||
{ |
|
||||||
IParser parser = GetParser(fileName); |
|
||||||
if (parser != null) { |
|
||||||
return parser.CreateExpressionFinder(fileName); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public static readonly string[] DefaultTaskListTokens = {"HACK", "TODO", "UNDONE", "FIXME"}; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the IParser instance that can parse the specified file.
|
|
||||||
/// This method is thread-safe.
|
|
||||||
/// </summary>
|
|
||||||
public static IParser GetParser(string fileName) |
|
||||||
{ |
|
||||||
if (fileName == null) |
|
||||||
throw new ArgumentNullException("fileName"); |
|
||||||
IParser curParser = null; |
|
||||||
foreach (ParserDescriptor descriptor in parser) { |
|
||||||
if (descriptor.CanParse(fileName)) { |
|
||||||
curParser = descriptor.Parser; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (curParser != null) { |
|
||||||
curParser.LexerTags = PropertyService.Get("SharpDevelop.TaskListTokens", DefaultTaskListTokens); |
|
||||||
} |
|
||||||
|
|
||||||
return curParser; |
|
||||||
} |
|
||||||
|
|
||||||
////////////////////////////////////
|
|
||||||
|
|
||||||
public static ArrayList CtrlSpace(int caretLine, int caretColumn, |
|
||||||
string fileName, string fileContent, ExpressionContext context) |
|
||||||
{ |
|
||||||
IResolver resolver = CreateResolver(fileName); |
|
||||||
if (resolver != null) { |
|
||||||
return resolver.CtrlSpace(caretLine, caretColumn, GetParseInformation(fileName), fileContent, context); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public static IResolver CreateResolver(string fileName) |
|
||||||
{ |
|
||||||
IParser parser = GetParser(fileName); |
|
||||||
if (parser != null) { |
|
||||||
return parser.CreateResolver(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public static ResolveResult Resolve(ExpressionResult expressionResult, |
|
||||||
int caretLineNumber, int caretColumn, |
|
||||||
string fileName, string fileContent) |
|
||||||
{ |
|
||||||
if (expressionResult.Region.IsEmpty) { |
|
||||||
expressionResult.Region = new DomRegion(caretLineNumber, caretColumn); |
|
||||||
} |
|
||||||
IResolver resolver = CreateResolver(fileName); |
|
||||||
if (resolver != null) { |
|
||||||
ParseInformation parseInfo = GetParseInformation(fileName); |
|
||||||
return resolver.Resolve(expressionResult, parseInfo, fileContent); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
static void OnParseInformationUpdated(ParseInformationEventArgs e) |
|
||||||
{ |
|
||||||
ParseInformationEventHandler handler = ParseInformationUpdated; |
|
||||||
if (handler != null) { |
|
||||||
handler(null, e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void OnLoadSolutionProjectsThreadEnded(EventArgs e) |
|
||||||
{ |
|
||||||
EventHandler handler = LoadSolutionProjectsThreadEnded; |
|
||||||
if (handler != null) { |
|
||||||
handler(null, e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static event EventHandler<ParseInformationEventArgs> ParseInformationUpdated = delegate {}; |
|
||||||
public static event EventHandler LoadSolutionProjectsThreadEnded; |
|
||||||
|
|
||||||
public static ProjectContentRegistry GetRegistryForReference(ReferenceProjectItem item) |
|
||||||
{ |
|
||||||
if (item is ProjectReferenceProjectItem || item.Project == null) { |
|
||||||
return defaultProjectContentRegistry; |
|
||||||
} |
|
||||||
foreach (ProjectContentRegistryDescriptor registry in registries) { |
|
||||||
if (registry.UseRegistryForProject(item.Project)) { |
|
||||||
ProjectContentRegistry r = registry.Registry; |
|
||||||
if (r != null) { |
|
||||||
return r; |
|
||||||
} else { |
|
||||||
return defaultProjectContentRegistry; // fallback when registry class not found
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return defaultProjectContentRegistry; |
|
||||||
} |
|
||||||
|
|
||||||
public static IProjectContent GetExistingProjectContentForReference(ReferenceProjectItem item) |
|
||||||
{ |
|
||||||
if (item is ProjectReferenceProjectItem) { |
|
||||||
if (((ProjectReferenceProjectItem)item).ReferencedProject == null) |
|
||||||
{ |
|
||||||
return null; |
|
||||||
} |
|
||||||
return ParserService.GetProjectContent(((ProjectReferenceProjectItem)item).ReferencedProject); |
|
||||||
} |
|
||||||
return GetRegistryForReference(item).GetExistingProjectContent(item.FileName); |
|
||||||
} |
|
||||||
|
|
||||||
public static IProjectContent GetProjectContentForReference(ReferenceProjectItem item) |
|
||||||
{ |
|
||||||
if (item is ProjectReferenceProjectItem) { |
|
||||||
if (((ProjectReferenceProjectItem)item).ReferencedProject == null) |
|
||||||
{ |
|
||||||
return null; |
|
||||||
} |
|
||||||
return ParserService.GetProjectContent(((ProjectReferenceProjectItem)item).ReferencedProject); |
|
||||||
} |
|
||||||
return GetRegistryForReference(item).GetProjectContentForReference(item.Include, item.FileName); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Refreshes the project content for the specified reference if required.
|
|
||||||
/// This method does nothing if the reference is not an assembly reference, is not loaded or already is up-to-date.
|
|
||||||
/// </summary>
|
|
||||||
public static void RefreshProjectContentForReference(ReferenceProjectItem item) |
|
||||||
{ |
|
||||||
if (item is ProjectReferenceProjectItem) { |
|
||||||
return; |
|
||||||
} |
|
||||||
ProjectContentRegistry registry = GetRegistryForReference(item); |
|
||||||
registry.RunLocked( |
|
||||||
delegate { |
|
||||||
IProjectContent rpc = GetExistingProjectContentForReference(item); |
|
||||||
if (rpc == null) { |
|
||||||
LoggingService.Debug("RefreshProjectContentForReference: not refreshing (rpc==null) " + item.FileName); |
|
||||||
return; |
|
||||||
} |
|
||||||
if (rpc.IsUpToDate) { |
|
||||||
LoggingService.Debug("RefreshProjectContentForReference: not refreshing (rpc.IsUpToDate) " + item.FileName); |
|
||||||
return; |
|
||||||
} |
|
||||||
LoggingService.Debug("RefreshProjectContentForReference " + item.FileName); |
|
||||||
|
|
||||||
HashSet<IProject> projectsToRefresh = new HashSet<IProject>(); |
|
||||||
HashSet<IProjectContent> unloadedReferenceContents = new HashSet<IProjectContent>(); |
|
||||||
UnloadReferencedContent(projectsToRefresh, unloadedReferenceContents, registry, rpc); |
|
||||||
|
|
||||||
foreach (IProject p in projectsToRefresh) { |
|
||||||
Reparse(p, true, false); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
static void UnloadReferencedContent(HashSet<IProject> projectsToRefresh, HashSet<IProjectContent> unloadedReferenceContents, ProjectContentRegistry referencedContentRegistry, IProjectContent referencedContent) |
|
||||||
{ |
|
||||||
LoggingService.Debug("Unload referenced content " + referencedContent); |
|
||||||
|
|
||||||
List<RegistryContentPair> otherContentsToUnload = new List<RegistryContentPair>(); |
|
||||||
foreach (ProjectContentRegistryDescriptor registry in registries) { |
|
||||||
if (registry.IsRegistryLoaded) { |
|
||||||
foreach (IProjectContent pc in registry.Registry.GetLoadedProjectContents()) { |
|
||||||
if (pc.ReferencedContents.Contains(referencedContent)) { |
|
||||||
if (unloadedReferenceContents.Add(pc)) { |
|
||||||
LoggingService.Debug("Mark dependent content for unloading " + pc); |
|
||||||
otherContentsToUnload.Add(new RegistryContentPair(registry.Registry, pc)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
foreach (IProjectContent pc in ParserService.AllProjectContents) { |
|
||||||
IProject project = (IProject)pc.Project; |
|
||||||
if (projectsToRefresh.Contains(project)) |
|
||||||
continue; |
|
||||||
if (pc.ReferencedContents.Remove(referencedContent)) { |
|
||||||
LoggingService.Debug("UnloadReferencedContent: Mark project for reparsing " + project.Name); |
|
||||||
projectsToRefresh.Add(project); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
foreach (RegistryContentPair pair in otherContentsToUnload) { |
|
||||||
UnloadReferencedContent(projectsToRefresh, unloadedReferenceContents, pair.Key, pair.Value); |
|
||||||
} |
|
||||||
|
|
||||||
referencedContentRegistry.UnloadProjectContent(referencedContent); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,87 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="Daniel Grunwald"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.Core |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Supports sorting codons using InsertBefore/InsertAfter
|
||||||
|
/// </summary>
|
||||||
|
static class TopologicalSort |
||||||
|
{ |
||||||
|
sealed class Node |
||||||
|
{ |
||||||
|
internal Codon codon; |
||||||
|
internal bool visited; |
||||||
|
internal List<Node> previous = new List<Node>(); |
||||||
|
|
||||||
|
internal void Visit(List<Codon> output) |
||||||
|
{ |
||||||
|
if (visited) |
||||||
|
return; |
||||||
|
visited = true; |
||||||
|
foreach (Node n in previous) |
||||||
|
n.Visit(output); |
||||||
|
output.Add(codon); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static List<Codon> Sort(IEnumerable<IEnumerable<Codon>> codonInput) |
||||||
|
{ |
||||||
|
// Step 1: create nodes for graph
|
||||||
|
Dictionary<string, Node> nameToNodeDict = new Dictionary<string, Node>(); |
||||||
|
List<Node> allNodes = new List<Node>(); |
||||||
|
foreach (IEnumerable<Codon> codonList in codonInput) { |
||||||
|
// create entries to preserve order within
|
||||||
|
Node previous = null; |
||||||
|
foreach (Codon codon in codonList) { |
||||||
|
Node node = new Node(); |
||||||
|
node.codon = codon; |
||||||
|
if (!string.IsNullOrEmpty(codon.Id)) |
||||||
|
nameToNodeDict[codon.Id] = node; |
||||||
|
// add implicit edges
|
||||||
|
if (previous != null) |
||||||
|
node.previous.Add(previous); |
||||||
|
|
||||||
|
allNodes.Add(node); |
||||||
|
previous = node; |
||||||
|
} |
||||||
|
} |
||||||
|
// Step 2: create edges from InsertBefore/InsertAfter values
|
||||||
|
foreach (Node node in allNodes) { |
||||||
|
if (!string.IsNullOrEmpty(node.codon.InsertBefore)) { |
||||||
|
foreach (string beforeReference in node.codon.InsertBefore.Split(',')) { |
||||||
|
Node referencedNode; |
||||||
|
if (nameToNodeDict.TryGetValue(beforeReference, out referencedNode)) { |
||||||
|
referencedNode.previous.Add(node); |
||||||
|
} else { |
||||||
|
LoggingService.WarnFormatted("Codon ({0}) specified in the insertbefore of the {1} codon does not exist!", beforeReference, node.codon); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (!string.IsNullOrEmpty(node.codon.InsertAfter)) { |
||||||
|
foreach (string afterReference in node.codon.InsertAfter.Split(',')) { |
||||||
|
Node referencedNode; |
||||||
|
if (nameToNodeDict.TryGetValue(afterReference, out referencedNode)) { |
||||||
|
node.previous.Add(referencedNode); |
||||||
|
} else { |
||||||
|
LoggingService.WarnFormatted("Codon ({0}) specified in the insertafter of the {1} codon does not exist!", afterReference, node.codon); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Step 3: Perform Topological Sort
|
||||||
|
List<Codon> output = new List<Codon>(); |
||||||
|
foreach (Node node in allNodes) { |
||||||
|
node.Visit(output); |
||||||
|
} |
||||||
|
return output; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue