@ -7,130 +7,114 @@ using System.IO;
using System.Linq ;
using System.Linq ;
using System.Threading ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Threading.Tasks ;
using ICSharpCode.Core ;
using ICSharpCode.Core ;
using ICSharpCode.Editor ;
using ICSharpCode.NRefactory.TypeSystem.Implementation ;
using ICSharpCode.SharpDevelop.Gui ;
using ICSharpCode.SharpDevelop.Gui ;
using ICSharpCode.SharpDevelop.Project ;
using ICSharpCode.SharpDevelop.Project ;
/ *
namespace ICSharpCode.SharpDevelop.Parser
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 )
public ParseProjectContent ( IProject project )
{
{
if ( project = = null )
if ( project = = null )
throw new ArgumentNullException ( "project" ) ;
throw new ArgumentNullException ( "project" ) ;
this . project = project ;
this . project = project ;
this . Language = project . LanguageProperties ;
this . initializing = true ;
this . initializing = true ;
LoadSolutionProjects . AddJob ( Initialize , "Loading " + project . Name + "..." , GetInitializationWorkAmount ( ) ) ;
}
}
readonly IProject project ;
public void Dispose ( )
{
public override object Project {
lock ( lockObj ) {
get {
ProjectService . ProjectItemAdded - = OnProjectItemAdded ;
return project ;
ProjectService . ProjectItemRemoved - = OnProjectItemRemoved ;
disposed = true ;
}
}
}
initializing = false ;
public string ProjectName {
get { return project . Name ; }
}
}
public override string AssemblyName {
public override string AssemblyName {
get { return project . AssemblyName ; }
get { return project . AssemblyName ; }
}
}
bool initializing ;
public override string ToString ( )
public override string ToString ( )
{
{
return string . Format ( "[{0}: {1}]" , GetType ( ) . Name , project . Name ) ;
return string . Format ( "[{0}: {1}]" , GetType ( ) . Name , project . Name ) ;
}
}
internal void Initialize1 ( IProgressMonitor progressMonitor )
int GetInitializationWorkAmount ( )
{
{
ICollection < ProjectItem > items = project . Items ;
return project . Items . Count + 1 5 ;
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 ) ;
}
}
internal void Re Initialize1 ( IProgressMonitor progressMonitor )
void Initialize ( IProgressMonitor progressMonitor )
{
{
var mscorlib = AssemblyParserService . GetRegistryForReference ( new ReferenceProjectItem ( project , "mscorlib" ) ) . Mscorlib ;
ICollection < ProjectItem > projectItems = project . Items ;
// don't fetch mscorlib within lock - finding the correct registry might access the project, causing
lock ( lockObj ) {
// a deadlock between IProject.SyncRoot and the ReferencedContents lock
if ( disposed ) {
lock ( ReferencedContents ) {
throw new ObjectDisposedException ( "ParseProjectContent" ) ;
ReferencedContents . Clear ( ) ;
}
AddReferencedContent ( mscorlib ) ;
ProjectService . ProjectItemAdded + = OnProjectItemAdded ;
ProjectService . ProjectItemRemoved + = OnProjectItemRemoved ;
}
}
// prevent adding event handler twice
using ( IProgressMonitor initReferencesProgressMonitor = progressMonitor . CreateSubTask ( 1 5 ) ,
ProjectService . ProjectItemAdded - = OnProjectItemAdded ;
parseProgressMonitor = progressMonitor . CreateSubTask ( projectItems . Count ) )
ProjectService . ProjectItemRemoved - = OnProjectItemRemoved ;
{
initializing = true ;
var resolveReferencesTask = ResolveReferencesAsync ( projectItems , initReferencesProgressMonitor ) ;
try {
Initialize1 ( p rogressMonitor) ;
ParseFiles ( projectItems , parseProgressMonitor ) ;
} finally {
initializing = false ;
resolveReferencesTask . Wait ( ) ;
}
}
}
}
void UpdateReferenceInterDependencies ( )
void ParseFiles ( ICollection < ProjectItem > projectItems , IProgressMonitor progressMonitor )
{
{
// Use ToArray because the collection could be modified inside the loop
ParseableFileContentFinder finder = new ParseableFileContentFinder ( ) ;
IProjectContent [ ] referencedContents ;
var fileContents = (
lock ( this . ReferencedContents ) {
from p in projectItems . AsParallel ( ) . WithCancellation ( progressMonitor . CancellationToken )
referencedContents = new IProjectContent [ this . ReferencedContents . Count ] ;
where ! ItemType . NonFileItemTypes . Contains ( p . ItemType ) & & ! String . IsNullOrEmpty ( p . FileName )
this . ReferencedContents . CopyTo ( referencedContents , 0 ) ;
select FileName . Create ( p . FileName )
}
) . ToList ( ) ;
foreach ( IProjectContent referencedContent in referencedContents ) {
if ( referencedContent is ReflectionProjectContent ) {
object progressLock = new object ( ) ;
( ( ReflectionProjectContent ) referencedContent ) . InitializeReferences ( ) ;
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 < ProjectItem > projectItems , IProgressMonitor progressMonitor )
{
{
try {
return System . Threading . Tasks . Task . Factory . StartNew (
AddReferencedContent ( AssemblyParserService . GetProjectContentForReference ( reference ) ) ;
delegate {
if ( updateInterDependencies ) {
project . ResolveAssemblyReferences ( ) ;
UpdateReferenceInterDependencies ( ) ;
} , progressMonitor . CancellationToken ) ;
}
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 ) ;
}
}
}
// ensure that com references are built serially because we cannot invoke multiple instances of MSBuild
// 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
project . Save ( ) ; // project is not yet saved when ItemAdded fires, so save it here
TaskService . BuildMessageViewCategory . AppendText ( "\n${res:MainWindow.CompilerMessages.CreatingCOMInteropAssembly}\n" ) ;
TaskService . BuildMessageViewCategory . AppendText ( "\n${res:MainWindow.CompilerMessages.CreatingCOMInteropAssembly}\n" ) ;
BuildCallback afterBuildCallback = delegate {
BuildCallback afterBuildCallback = delegate {
ReparseReferences ( ) ;
lock ( callAfterAddComReference ) {
lock ( callAfterAddComReference ) {
if ( callAfterAddComReference . Count > 0 ) {
if ( callAfterAddComReference . Count > 0 ) {
// run next enqueued action
// run next enqueued action
callAfterAddComReference . Dequeue ( ) ( ) ;
callAfterAddComReference . Dequeue ( ) ( ) ;
} else {
} else {
buildingComReference = false ;
buildingComReference = false ;
ParserService . Reparse ( project , true , false ) ;
}
}
}
}
} ;
} ;
@ -173,18 +157,24 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
}
}
} else {
} else {
ParserService . Reparse ( project , true , false ) ;
ReparseReferences ( ) ;
}
}
}
}
if ( e . ProjectItem . ItemType = = ItemType . Import ) {
if ( e . ProjectItem . ItemType = = ItemType . Import ) {
UpdateDefaultImports ( project . Items ) ;
throw new NotImplementedException ( ) ;
//UpdateDefaultImports(project.Items);
} else if ( e . ProjectItem . ItemType = = ItemType . Compile ) {
} else if ( e . ProjectItem . ItemType = = ItemType . Compile ) {
if ( System . IO . File . Exists ( e . ProjectItem . FileName ) ) {
if ( System . IO . File . Exists ( e . ProjectItem . FileName ) ) {
ParserService . BeginPars e( e . ProjectItem . FileName ) ;
ParserService . ParseFileAsync ( FileName . Creat e( e . ProjectItem . FileName ) ) ;
}
}
}
}
}
}
void ReparseReferences ( )
{
throw new NotImplementedException ( ) ;
}
void OnProjectItemRemoved ( object sender , ProjectItemEventArgs e )
void OnProjectItemRemoved ( object sender , ProjectItemEventArgs e )
{
{
if ( e . Project ! = project ) return ;
if ( e . Project ! = project ) return ;
@ -192,25 +182,21 @@ namespace ICSharpCode.SharpDevelop.Parser
ReferenceProjectItem reference = e . ProjectItem as ReferenceProjectItem ;
ReferenceProjectItem reference = e . ProjectItem as ReferenceProjectItem ;
if ( reference ! = null ) {
if ( reference ! = null ) {
try {
try {
IProjectContent referencedContent = AssemblyParserService . GetExistingProjectContentForReference ( reference ) ;
ReparseReferences ( ) ;
if ( referencedContent ! = null ) {
lock ( ReferencedContents ) {
ReferencedContents . Remove ( referencedContent ) ;
}
OnReferencedContentsChanged ( EventArgs . Empty ) ;
}
} catch ( Exception ex ) {
} catch ( Exception ex ) {
MessageService . ShowException ( ex ) ;
MessageService . ShowException ( ex ) ;
}
}
}
}
if ( e . ProjectItem . ItemType = = ItemType . Import ) {
if ( e . ProjectItem . ItemType = = ItemType . Import ) {
UpdateDefaultImports ( project . Items ) ;
throw new NotImplementedException ( ) ;
//UpdateDefaultImports(project.Items);
} else if ( e . ProjectItem . ItemType = = ItemType . Compile ) {
} else if ( e . ProjectItem . ItemType = = ItemType . Compile ) {
ParserService . ClearParseInformation ( e . ProjectItem . FileName ) ;
ParserService . ClearParseInformation ( FileName . Create ( e . ProjectItem . FileName ) ) ;
}
}
}
}
/ *
int languageDefaultImportCount = - 1 ;
int languageDefaultImportCount = - 1 ;
void UpdateDefaultImports ( ICollection < ProjectItem > items )
void UpdateDefaultImports ( ICollection < ProjectItem > items )
@ -233,77 +219,6 @@ namespace ICSharpCode.SharpDevelop.Parser
DefaultImports . Usings . Add ( item . Include ) ;
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 ( ) ;
}
}
}
}
}
* /