diff --git a/TODOnewNR.txt b/TODOnewNR.txt index 2a37df220e..be62e544c6 100644 --- a/TODOnewNR.txt +++ b/TODOnewNR.txt @@ -22,14 +22,55 @@ Stuff that was renamed/moved: IReturnType -> ITypeReference (unresolved) or IType (resolved) Location -> TextLocation in ICSharpCode.NRefactory TextLocation -> moved to ICSharpCode.NRefactory - ParserService -> SD.ParserService Functionality changes: - The result of a parser run (ParseInformation) now may contain a fully parsed AST. - The ParserService may cache such full ASTs, but may also drop them from memory at any time. - This will be implemented by keeping the last N accessed files in the cache. (currently we just keep the caches around forever) - Every parse information also contains an IParsedFile instance with the type system information. - The IParsedFile is stored permanently (both in ParserService and in the IProjectContents). + + Static services replaced with interfaces: + To make writing unit tests easier, the static services in SharpDevelop are getting + replaced with interfaces. The class "SD" has static properties to get references + to the services, so the call "ResourceService.GetString()" becomes "SD.ResourceService.GetString()". + + In unit tests, Rhino.Mocks can be used to easily create mocks of the services: + SD.InitializeForUnitTests(); // removes services from previous test cases + SD.Services.AddService(typeof(IParserService), MockRepository.GenerateStrictMock()); + SD.ParserService.Stub(p => p.GetCachedParseInformation(textEditor.FileName)).Return(parseInfo); + SD.ParserService.Stub(p => p.GetCompilationForFile(textEditor.FileName)).Return(compilation); + + It is possible to define a service interface in ICSharpCode.SharpDevelop.dll and have the implementation + somewhere else (SD will find it using the AddInTree). + This allows for AddIns to consume each other's functionality (e.g. debugger accessing the decompiler service) + without having to define a custom extension point. + The long-term goal is to have only interfaces and helper classes in ICSharpCode.SharpDevelop.dll (the API for AddIns) + and have the implementation details in SharpDevelop.exe (which AddIns aren't supposed to reference). + + + SD.MainThread: + The new best way to invoke a call on the main thread is: + SD.MainThread.InvokeAsync(delegate { ... }).FireAndForget(); + + Note that InvokeAsync returns a Task (like all .NET 4.5 *Async APIs). If any exceptions occur while + executing the delegate, they will get stored in the task object. This can cause the exception to get + silently ignored if the task object isn't used later. The "FireAndForget()" extension method solves + this problem by reporting any (future) errors to the message service. + + + SD.PropertyService: + The Get()/Set() methods no longer support nested Properties objects or lists of elements - + you will need to use the new dedicated GetList()/SetList()/NestedProperties() methods for that. + + The Get() method no longer causes the default value to be stored in the container; and GetList() + results in a read-only list - an explicit SetList() call is required to store the resulting value again. + + However, a nested properties container still is connected with its parent, and any changes done + to the nested container will get saves without having to call the SetNestedProperties() method. + + + SD.ParserService: + The result of a parser run (ParseInformation) now may contain a fully parsed AST. + The ParserService may cache such full ASTs, but may also drop them from memory at any time. + This will be implemented by keeping the last N accessed files in the cache. (currently we just keep the caches around forever) + Every parse information also contains an IParsedFile instance with the type system information. + The IParsedFile is stored permanently (both in ParserService and in the IProjectContents). Context Actions vs. Member Context Menu: diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd b/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd index ad7c12346a..facdaaec06 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd @@ -35,6 +35,7 @@ + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs index ed7da3128d..6c87e36571 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs @@ -33,10 +33,12 @@ namespace CSharpBinding readonly HighlightingColor fieldAccessColor; readonly HighlightingColor valueKeywordColor; readonly HighlightingColor parameterModifierColor; + readonly HighlightingColor inactiveCodeColor; List invalidLines = new List(); List cachedLines = new List(); bool hasCrashed; + bool forceParseOnNextRefresh; int lineNumber; HighlightedLine line; @@ -61,6 +63,7 @@ namespace CSharpBinding this.fieldAccessColor = highlightingDefinition.GetNamedColor("FieldAccess"); this.valueKeywordColor = highlightingDefinition.GetNamedColor("NullOrValueKeywords"); this.parameterModifierColor = highlightingDefinition.GetNamedColor("ParameterModifiers"); + this.inactiveCodeColor = highlightingDefinition.GetNamedColor("InactiveCode"); SD.ParserService.ParseInformationUpdated += ParserService_ParseInformationUpdated; SD.ParserService.LoadSolutionProjectsThread.Finished += ParserService_LoadSolutionProjectsThreadEnded; @@ -146,6 +149,7 @@ namespace CSharpBinding { cachedLines.Clear(); invalidLines.Clear(); + forceParseOnNextRefresh = true; syntaxHighlighter.InvalidateAll(); } @@ -208,7 +212,13 @@ namespace CSharpBinding return cachedLine.HighlightedLine; } - var parseInfo = SD.ParserService.GetCachedParseInformation(textEditor.FileName, textEditor.Document.Version) as CSharpFullParseInformation; + CSharpFullParseInformation parseInfo; + if (forceParseOnNextRefresh) { + forceParseOnNextRefresh = false; + parseInfo = SD.ParserService.Parse(textEditor.FileName, textEditor.Document) as CSharpFullParseInformation; + } else { + parseInfo = SD.ParserService.GetCachedParseInformation(textEditor.FileName, textEditor.Document.Version) as CSharpFullParseInformation; + } if (parseInfo == null) { if (!invalidLines.Contains(documentLine)) invalidLines.Add(documentLine); @@ -278,10 +288,10 @@ namespace CSharpBinding { if (color == null) return; - if (start.Line == lineNumber && end.Line == lineNumber) { + if (start.Line <= lineNumber && end.Line >= lineNumber) { int lineStartOffset = line.DocumentLine.Offset; - int startOffset = lineStartOffset + start.Column - 1; - int endOffset = lineStartOffset + end.Column - 1; + int startOffset = lineStartOffset + (start.Line == lineNumber ? start.Column - 1 : 0); + int endOffset = lineStartOffset + (end.Line == lineNumber ? end.Column - 1 : line.DocumentLine.Length); if (line.Sections.Count > 0) { HighlightedSection prevSection = line.Sections.Last(); if (startOffset < prevSection.Offset + prevSection.Length) @@ -347,12 +357,18 @@ namespace CSharpBinding { Expression target = invocationExpression.Target; if (target is IdentifierExpression || target is MemberReferenceExpression || target is PointerReferenceExpression) { + var invocationRR = resolver.Resolve(invocationExpression) as CSharpInvocationResolveResult; + if (invocationRR != null && IsInactiveConditionalMethod(invocationRR.Member)) { + // mark the whole invocation expression as inactive code + Colorize(invocationExpression, inactiveCodeColor); + return; + } + // apply color to target's target target.GetChildByRole(Roles.TargetExpression).AcceptVisitor(this); // highlight the method call var identifier = target.GetChildByRole(Roles.Identifier); - var invocationRR = resolver.Resolve(invocationExpression) as CSharpInvocationResolveResult; if (invocationRR != null && !invocationRR.IsDelegateInvocation) { Colorize(identifier, methodCallColor); } else { @@ -364,8 +380,38 @@ namespace CSharpBinding } else { target.AcceptVisitor(this); } - - invocationExpression.Arguments.AcceptVisitor(this); + // Visit arguments and comments within the arguments: + for (AstNode child = target.NextSibling; child != null; child = child.NextSibling) { + child.AcceptVisitor(this); + } + } + + bool IsInactiveConditionalMethod(IParameterizedMember member) + { + if (member.EntityType != EntityType.Method || member.ReturnType.Kind != TypeKind.Void) + return false; + while (member.IsOverride) + member = (IParameterizedMember)InheritanceHelper.GetBaseMember(member); + return IsInactiveConditional(member.Attributes); + } + + bool IsInactiveConditional(IList attributes) + { + bool hasConditionalAttribute = false; + foreach (var attr in attributes) { + if (attr.AttributeType.Name == "ConditionalAttribute" && attr.AttributeType.Namespace == "System.Diagnostics" && attr.PositionalArguments.Count == 1) { + string symbol = attr.PositionalArguments[0].ConstantValue as string; + if (symbol != null) { + hasConditionalAttribute = true; + var cu = this.resolver.RootNode as CompilationUnit; + if (cu != null) { + if (cu.ConditionalSymbols.Contains(symbol)) + return false; // conditional is active + } + } + } + } + return hasConditionalAttribute; } public override void VisitAccessor(Accessor accessor) @@ -380,34 +426,40 @@ namespace CSharpBinding public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) { - //methodDeclaration.Attributes.AcceptVisitor(this); - methodDeclaration.ReturnType.AcceptVisitor(this); - methodDeclaration.PrivateImplementationType.AcceptVisitor(this); - Colorize(methodDeclaration.NameToken, methodCallColor); - methodDeclaration.TypeParameters.AcceptVisitor(this); - methodDeclaration.Parameters.AcceptVisitor(this); - methodDeclaration.Constraints.AcceptVisitor(this); - methodDeclaration.Body.AcceptVisitor(this); + for (AstNode child = methodDeclaration.FirstChild; child != null; child = child.NextSibling) { + if (child.StartLocation.Line <= lineNumber && child.EndLocation.Line >= lineNumber) { + if (child.Role == Roles.Identifier) { + // child == methodDeclaration.NameToken + Colorize(child, methodCallColor); + } else { + child.AcceptVisitor(this); + } + } + } } public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) { - //typeDeclaration.Attributes.AcceptVisitor(this); - - if (typeDeclaration.ClassType == ClassType.Enum || typeDeclaration.ClassType == ClassType.Struct) - Colorize(typeDeclaration.NameToken, valueTypeColor); - else - Colorize(typeDeclaration.NameToken, referenceTypeColor); - - typeDeclaration.TypeParameters.AcceptVisitor(this); - typeDeclaration.BaseTypes.AcceptVisitor(this); - typeDeclaration.Constraints.AcceptVisitor(this); - typeDeclaration.Members.AcceptVisitor(this); + // Type declarations often contain #if directives, so we must make sure + // to also visit the comments. + for (AstNode child = typeDeclaration.FirstChild; child != null; child = child.NextSibling) { + if (child.StartLocation.Line <= lineNumber && child.EndLocation.Line >= lineNumber) { + if (child.Role == Roles.Identifier) { + // child == typeDeclaration.NameToken + if (typeDeclaration.ClassType == ClassType.Enum || typeDeclaration.ClassType == ClassType.Struct) + Colorize(typeDeclaration.NameToken, valueTypeColor); + else + Colorize(typeDeclaration.NameToken, referenceTypeColor); + } else { + child.AcceptVisitor(this); + } + } + } } public override void VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) { - //typeParameterDeclaration.Attributes.AcceptVisitor(this); + typeParameterDeclaration.Attributes.AcceptVisitor(this); if (typeParameterDeclaration.Variance == VarianceModifier.Contravariant) Colorize(typeParameterDeclaration.VarianceToken, parameterModifierColor); @@ -440,6 +492,13 @@ namespace CSharpBinding } variableInitializer.Initializer.AcceptVisitor(this); } + + public override void VisitComment(Comment comment) + { + if (comment.CommentType == CommentType.InactiveCode) { + Colorize(comment, inactiveCodeColor); + } + } #endregion } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Tests/OverrideCompletionTests.cs b/src/AddIns/BackendBindings/CSharpBinding/Tests/OverrideCompletionTests.cs index ebe66f88a2..b7baa73dcc 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Tests/OverrideCompletionTests.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Tests/OverrideCompletionTests.cs @@ -57,7 +57,7 @@ class DerivedClass : BaseClass { var pc = new CSharpProjectContent().UpdateProjectContent(null, parseInfo.ParsedFile); pc = pc.AddAssemblyReferences(new[] { Corlib }); var compilation = pc.CreateCompilation(); - SD.Services.AddService(typeof(IParserService), MockRepository.GenerateStub()); + SD.Services.AddService(typeof(IParserService), MockRepository.GenerateStrictMock()); SD.ParserService.Stub(p => p.GetCachedParseInformation(textEditor.FileName)).Return(parseInfo); SD.ParserService.Stub(p => p.GetCompilationForFile(textEditor.FileName)).Return(compilation); CSharpCompletionBinding completion = new CSharpCompletionBinding(); diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 318070e7c9..c43bf3872b 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -740,6 +740,7 @@ + diff --git a/src/Main/Base/Project/Src/Project/CompilableProject.cs b/src/Main/Base/Project/Src/Project/CompilableProject.cs index bd46ce2090..0b24daf567 100644 --- a/src/Main/Base/Project/Src/Project/CompilableProject.cs +++ b/src/Main/Base/Project/Src/Project/CompilableProject.cs @@ -238,9 +238,14 @@ namespace ICSharpCode.SharpDevelop.Project lock (SyncRoot) { if (parseProjectContentContainer == null) return; // parsing hasn't started yet; no need to re-parse + if (references) { + parseProjectContentContainer.ReparseReferences(); + } + if (code) { + parseProjectContentContainer.SetCompilerSettings(CreateCompilerSettings()); + parseProjectContentContainer.ReparseCode(); + } } - #warning Reparse - throw new NotImplementedException(); } [Browsable(false)] diff --git a/src/Main/Base/Project/Src/Project/MSBuildInternals.cs b/src/Main/Base/Project/Src/Project/MSBuildInternals.cs index 3511d1d459..e73748ba63 100644 --- a/src/Main/Base/Project/Src/Project/MSBuildInternals.cs +++ b/src/Main/Base/Project/Src/Project/MSBuildInternals.cs @@ -205,7 +205,7 @@ namespace ICSharpCode.SharpDevelop.Project } List targets = new List(); - if (baseProject.HasProjectType(ProjectTypeGuids.PortableLibrary)) { + if (baseProject.MinimumSolutionVersion >= Solution.SolutionVersionVS2010) { targets.Add("ResolveReferences"); targets.Add("DesignTimeResolveAssemblyReferences"); } else { diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index f139991747..df7b4332a9 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -46,6 +46,7 @@ namespace ICSharpCode.SharpDevelop.Parser string cacheFileName; + #region Constructor + Dispose public ParseProjectContentContainer(MSBuildBasedProject project, IProjectContent initialProjectContent) { if (project == null) @@ -92,6 +93,7 @@ namespace ICSharpCode.SharpDevelop.Parser if (serializeOnDispose) SerializeAsync(cacheFileName, pc).FireAndForget(); } + #endregion #region Caching logic (serialization) @@ -228,13 +230,7 @@ namespace ICSharpCode.SharpDevelop.Parser } } - bool IsParseableFile(FileProjectItem projectItem) - { - if (projectItem == null || string.IsNullOrEmpty(projectItem.FileName)) - return false; - return projectItem.ItemType == ItemType.Compile || projectItem.ItemType == ItemType.Page; - } - + #region Initialize void Initialize(IProgressMonitor progressMonitor, List filesToParse) { ICollection projectItems = project.Items; @@ -248,16 +244,29 @@ namespace ICSharpCode.SharpDevelop.Parser using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(LoadingReferencesWorkAmount * scalingFactor), parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count * scalingFactor)) { - var resolveReferencesTask = ResolveReferencesAsync(projectItems, initReferencesProgressMonitor); + var resolveReferencesTask = Task.Run( + delegate { + DoResolveReferences(projectItems, initReferencesProgressMonitor); + }, initReferencesProgressMonitor.CancellationToken); ParseFiles(filesToParse, parseProgressMonitor); resolveReferencesTask.Wait(); } } + #endregion - void ParseFiles(IReadOnlyList filesToParse, IProgressMonitor progressMonitor) + #region ParseFiles + bool IsParseableFile(FileProjectItem projectItem) { + if (projectItem == null || string.IsNullOrEmpty(projectItem.FileName)) + return false; + return projectItem.ItemType == ItemType.Compile || projectItem.ItemType == ItemType.Page; + } + + void ParseFiles(List filesToParse, IProgressMonitor progressMonitor) + { + IParserService parserService = SD.ParserService; IProjectContent cachedPC = TryReadFromCache(cacheFileName); ParseableFileContentFinder finder = new ParseableFileContentFinder(); @@ -279,7 +288,7 @@ namespace ICSharpCode.SharpDevelop.Parser if (content == null && cachedPC != null) { parsedFile = cachedPC.GetFile(fileName); if (parsedFile != null && parsedFile.LastWriteTime == File.GetLastWriteTimeUtc(fileName)) { - SD.ParserService.RegisterParsedFile(fileName, project, parsedFile); + parserService.RegisterParsedFile(fileName, project, parsedFile); wasLoadedFromCache = true; } } @@ -292,7 +301,7 @@ namespace ICSharpCode.SharpDevelop.Parser } } if (content != null) { - parsedFile = SD.ParserService.ParseFile(fileName, content, project); + parsedFile = parserService.ParseFile(fileName, content, project); } } lock (progressLock) { @@ -314,88 +323,111 @@ namespace ICSharpCode.SharpDevelop.Parser } } - Task ResolveReferencesAsync(ICollection projectItems, IProgressMonitor progressMonitor) + AtomicBoolean reparseCodeStartedButNotYetRunning; + + public void ReparseCode() { - return Task.Run( - delegate { - var referenceItems = project.ResolveAssemblyReferences(progressMonitor.CancellationToken); - const double assemblyResolvingProgress = 0.3; // 30% asm resolving, 70% asm loading - progressMonitor.Progress += assemblyResolvingProgress; - progressMonitor.CancellationToken.ThrowIfCancellationRequested(); - - List assemblyFiles = new List(); - List newReferences = new List(); - - foreach (var reference in referenceItems) { - ProjectReferenceProjectItem projectReference = reference as ProjectReferenceProjectItem; - if (projectReference != null) { - newReferences.Add(projectReference); - } else { - assemblyFiles.Add(reference.FileName); - } + if (reparseCodeStartedButNotYetRunning.Set()) { + var filesToParse = ( + from item in project.Items.OfType() + where IsParseableFile(item) + select FileName.Create(item.FileName) + ).ToList(); + SD.ParserService.LoadSolutionProjectsThread.AddJob( + monitor => { + reparseCodeStartedButNotYetRunning.Reset(); + DoReparseCode(filesToParse, monitor); + }, + "Loading " + project.Name + "...", filesToParse.Count); + } + } + + void DoReparseCode(List filesToParse, IProgressMonitor progressMonitor) + { + IParserService parserService = SD.ParserService; + ParseableFileContentFinder finder = new ParseableFileContentFinder(); + double fileCountInverse = 1.0 / filesToParse.Count; + object progressLock = new object(); + Parallel.ForEach( + filesToParse, + new ParallelOptions { + MaxDegreeOfParallelism = Environment.ProcessorCount, + CancellationToken = progressMonitor.CancellationToken + }, + fileName => { + ITextSource content = finder.Create(fileName); + if (content != null) { + parserService.ParseFile(fileName, content, project); } - - foreach (string file in assemblyFiles) { - progressMonitor.CancellationToken.ThrowIfCancellationRequested(); - if (File.Exists(file)) { - var pc = SD.AssemblyParserService.GetAssembly(FileName.Create(file), progressMonitor.CancellationToken); - if (pc != null) { - newReferences.Add(pc); - } - } - progressMonitor.Progress += (1.0 - assemblyResolvingProgress) / assemblyFiles.Count; + lock (progressLock) { + progressMonitor.Progress += fileCountInverse; } - lock (lockObj) { - projectContent = projectContent.RemoveAssemblyReferences(this.references).AddAssemblyReferences(newReferences); - this.references = newReferences.ToArray(); - SD.ParserService.InvalidateCurrentSolutionSnapshot(); + }); + } + #endregion + + #region ResolveReferences + void DoResolveReferences(ICollection projectItems, IProgressMonitor progressMonitor) + { + var referenceItems = project.ResolveAssemblyReferences(progressMonitor.CancellationToken); + const double assemblyResolvingProgress = 0.3; // 30% asm resolving, 70% asm loading + progressMonitor.Progress += assemblyResolvingProgress; + progressMonitor.CancellationToken.ThrowIfCancellationRequested(); + + List assemblyFiles = new List(); + List newReferences = new List(); + + foreach (var reference in referenceItems) { + ProjectReferenceProjectItem projectReference = reference as ProjectReferenceProjectItem; + if (projectReference != null) { + newReferences.Add(projectReference); + } else { + assemblyFiles.Add(reference.FileName); + } + } + + foreach (string file in assemblyFiles) { + progressMonitor.CancellationToken.ThrowIfCancellationRequested(); + if (File.Exists(file)) { + var pc = SD.AssemblyParserService.GetAssembly(FileName.Create(file), progressMonitor.CancellationToken); + if (pc != null) { + newReferences.Add(pc); } - }, progressMonitor.CancellationToken); + } + progressMonitor.Progress += (1.0 - assemblyResolvingProgress) / assemblyFiles.Count; + } + lock (lockObj) { + if (!disposed) { + projectContent = projectContent.RemoveAssemblyReferences(this.references).AddAssemblyReferences(newReferences); + this.references = newReferences.ToArray(); + SD.ParserService.InvalidateCurrentSolutionSnapshot(); + } + } } - // ensure that com references are built serially because we cannot invoke multiple instances of MSBuild - static Queue callAfterAddComReference = new Queue(); - static bool buildingComReference; + AtomicBoolean reparseReferencesStartedButNotYetRunning; + public void ReparseReferences() + { + if (reparseReferencesStartedButNotYetRunning.Set()) { + SD.ParserService.LoadSolutionProjectsThread.AddJob( + monitor => { + reparseReferencesStartedButNotYetRunning.Reset(); + DoResolveReferences(project.Items, monitor); + }, + "Loading " + project.Name + "...", LoadingReferencesWorkAmount); + } + } + #endregion + + #region Project Item Added/Removed void OnProjectItemAdded(object sender, ProjectItemEventArgs e) { if (e.Project != project) return; ReferenceProjectItem reference = e.ProjectItem as ReferenceProjectItem; if (reference != null) { - if (reference.ItemType == ItemType.COMReference) { - Action action = delegate { - // Compile project to ensure interop library is generated - project.Save(); // project is not yet saved when ItemAdded fires, so save it here - string message = StringParser.Parse("\n${res:MainWindow.CompilerMessages.CreatingCOMInteropAssembly}\n"); - TaskService.BuildMessageViewCategory.AppendText(message); - BuildCallback afterBuildCallback = delegate { - ReparseReferences(); - lock (callAfterAddComReference) { - if (callAfterAddComReference.Count > 0) { - // run next enqueued action - callAfterAddComReference.Dequeue()(); - } else { - buildingComReference = false; - } - } - }; - BuildEngine.BuildInGui(project, new BuildOptions(BuildTarget.ResolveComReferences, afterBuildCallback)); - }; - - // enqueue actions when adding multiple COM references so that multiple builds of the same project - // are not started parallely - lock (callAfterAddComReference) { - if (buildingComReference) { - callAfterAddComReference.Enqueue(action); - } else { - buildingComReference = true; - action(); - } - } - } else { - ReparseReferences(); - } + ReparseReferences(); } FileProjectItem fileProjectItem = e.ProjectItem as FileProjectItem; if (IsParseableFile(fileProjectItem)) { @@ -404,11 +436,6 @@ namespace ICSharpCode.SharpDevelop.Parser } } - void ReparseReferences() - { - throw new NotImplementedException(); - } - void OnProjectItemRemoved(object sender, ProjectItemEventArgs e) { if (e.Project != project) return; @@ -427,5 +454,6 @@ namespace ICSharpCode.SharpDevelop.Parser SD.ParserService.RemoveOwnerProject(FileName.Create(e.ProjectItem.FileName), project); } } + #endregion } } diff --git a/src/Main/Base/Project/Src/Util/AtomicBoolean.cs b/src/Main/Base/Project/Src/Util/AtomicBoolean.cs new file mode 100644 index 0000000000..637c133454 --- /dev/null +++ b/src/Main/Base/Project/Src/Util/AtomicBoolean.cs @@ -0,0 +1,60 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Threading; + +namespace ICSharpCode.SharpDevelop +{ + /// + /// A boolean that starts 'false' and can be atomically set/reset. + /// + public struct AtomicBoolean + { + int val; + + /// + /// Gets/Sets the value. + /// + public bool Value { + get { + return Volatile.Read(ref val) != 0; + } + set { + Volatile.Write(ref val, value ? 1 : 0); + } + } + + /// + /// Sets the value to true. + /// + /// True if the value was successfully set from false to true, + /// false if the value already was true. + public bool Set() + { + return Interlocked.Exchange(ref val, 1) == 0; + } + + /// + /// Sets the value to false. + /// + /// True if the value was successfully set from true to false, + /// false if the value already was false. + public bool Reset() + { + return Interlocked.Exchange(ref val, 0) != 0; + } + + /// + public override int GetHashCode() + { + return this.Value.GetHashCode(); + } + + /// + public override bool Equals(object obj) + { + return (obj is AtomicBoolean) && val == ((AtomicBoolean)obj).val; + } + } +} diff --git a/src/Main/Core/Project/Src/AddInTree/AddInManager.cs b/src/Main/Core/Project/Src/AddInTree/AddInManager.cs index 9384c64eac..c29e9e6a69 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddInManager.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddInManager.cs @@ -265,7 +265,7 @@ namespace ICSharpCode.Core /// /// /// The list of AddIns to add. (use instances - /// created by ). + /// created by ). /// public static void AddExternalAddIns(IList addIns) { @@ -289,7 +289,7 @@ namespace ICSharpCode.Core /// AddIns. /// /// The list of AddIns to remove. - /// (use external AddIns from the collection). + /// (use external AddIns from the collection). public static void RemoveExternalAddIns(IList addIns) { List addInFiles = new List();