diff options
author | Lluis Sanchez <lluis@xamarin.com> | 2015-09-10 13:44:43 +0300 |
---|---|---|
committer | Lluis Sanchez <lluis@xamarin.com> | 2015-09-10 13:45:03 +0300 |
commit | 25b732404d038f0b9cf166ec6834062dd4be75e2 (patch) | |
tree | ba9b3ae9f38fa772ed0efb092abdf41060068493 /main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild | |
parent | 9bfc594738571de676e01585c984cd526e9f66c8 (diff) |
[Core] Make MSBuildProject thread safe for reading
Diffstat (limited to 'main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild')
12 files changed, 145 insertions, 79 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildChoose.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildChoose.cs index 036680196d..dec11b4c0a 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildChoose.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildChoose.cs @@ -42,7 +42,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (op != null) { op.ParentNode = this; op.Read (reader); - ChildNodes.Add (op); + ChildNodes = ChildNodes.Add (op); } else base.ReadChildElement (reader); } @@ -86,7 +86,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (ob != null) { ob.ParentNode = this; ob.Read (reader); - ChildNodes.Add (ob); + ChildNodes = ChildNodes.Add (ob); } else reader.Read (); } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs index 5db3d39c11..91bcbeaa9a 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs @@ -64,7 +64,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public string Project { get { return target; } - set { target = value; NotifyChanged (); } + set { AssertCanModify (); target = value; NotifyChanged (); } } public string EvaluatedProject { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImportGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImportGroup.cs index 58b801e693..afc3d07757 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImportGroup.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImportGroup.cs @@ -38,7 +38,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild var item = new MSBuildImport (); item.ParentNode = this; item.Read (reader); - ChildNodes.Add (item); + ChildNodes = ChildNodes.Add (item); } else base.ReadChildElement (reader); } @@ -55,6 +55,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public MSBuildImport AddNewImport (string name, string condition = null, MSBuildImport beforeImport = null) { + AssertCanModify (); var import = new MSBuildImport (); import.Project = name; import.Condition = condition; @@ -64,9 +65,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild insertIndex = ChildNodes.IndexOf (beforeImport); if (insertIndex != -1) - ChildNodes.Insert (insertIndex, import); + ChildNodes = ChildNodes.Insert (insertIndex, import); else - ChildNodes.Add (import); + ChildNodes = ChildNodes.Add (import); import.ResetIndent (false); NotifyChanged (); @@ -75,9 +76,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveImport (MSBuildImport import) { + AssertCanModify (); if (import.ParentObject == this) { import.RemoveIndent (); - ChildNodes.Remove (import); + ChildNodes = ChildNodes.Remove (import); NotifyChanged (); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs index c0a1a5ec9a..59b1a416b7 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs @@ -35,7 +35,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild public class MSBuildItem: MSBuildElement { MSBuildPropertyGroup metadata; - MSBuildPropertyGroupEvaluated evaluatedMetadata; string name; string include; string exclude; @@ -113,6 +112,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public string Include { get { return include; } set { + AssertCanModify (); include = value; NotifyChanged (); } @@ -121,6 +121,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public string Exclude { get { return exclude; } set { + AssertCanModify (); exclude = value; NotifyChanged (); } @@ -141,14 +142,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - public IMSBuildPropertyGroupEvaluated EvaluatedMetadata { - get { - if (evaluatedMetadata == null) - evaluatedMetadata = new MSBuildPropertyGroupEvaluated (ParentProject); - return evaluatedMetadata; - } - } - internal int EvaluatedItemCount { get; set; } internal bool IsWildcardItem { @@ -169,6 +162,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild this.include = include; this.evaluatedInclude = evaluatedInclude; this.parent = parent; + metadata = new MSBuildPropertyGroupEvaluated (parent); Name = name; } @@ -193,8 +187,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild public IMSBuildPropertyGroupEvaluated Metadata { get { - if (metadata == null) - metadata = new MSBuildPropertyGroupEvaluated (parent); return metadata; } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs index 6fde109101..37bd43bea2 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs @@ -38,7 +38,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild var item = new MSBuildItem (); item.ParentNode = this; item.Read (reader); - ChildNodes.Add (item); + ChildNodes = ChildNodes.Add (item); } internal override string GetElementName () @@ -53,6 +53,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public MSBuildItem AddNewItem (string name, string include) { + AssertCanModify (); var it = new MSBuildItem (name); it.Include = include; AddItem (it); @@ -61,8 +62,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void AddItem (MSBuildItem item) { - ChildNodes.Add (item); + AssertCanModify (); item.ParentNode = this; + ChildNodes = ChildNodes.Add (item); item.ResetIndent (false); if (ParentProject != null) ParentProject.NotifyChanged (); @@ -76,9 +78,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild internal void RemoveItem (MSBuildItem item) { + AssertCanModify (); if (ChildNodes.Contains (item)) { item.RemoveIndent (); - ChildNodes.Remove (item); + ChildNodes = ChildNodes.Remove (item); NotifyChanged (); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs index d86e28ee0b..565de09aa3 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable;
using System.Linq; using System.Xml; @@ -38,7 +39,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild { UnknownAttribute[] unknownAttributes; string [] attributeOrder; - List<MSBuildNode> children; + ImmutableList<MSBuildNode> children = ImmutableList<MSBuildNode>.Empty; EmptyElementMode emptyElementMode; enum EmptyElementMode : byte @@ -185,7 +186,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } var tn = new MSBuildXmlTextNode (); tn.Read (reader); - ChildNodes.Add (tn); + ChildNodes = ChildNodes.Add (tn); } else if (reader.NodeType == XmlNodeType.CDATA) { if (!childFound) { childFound = true; @@ -193,7 +194,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } var tn = new MSBuildXmlCDataNode (); tn.Read (reader); - ChildNodes.Add (tn); + ChildNodes = ChildNodes.Add (tn); } else if (reader.NodeType == XmlNodeType.Comment) { if (!childFound) { childFound = true; @@ -201,7 +202,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } var tn = new MSBuildXmlCommentNode (); tn.Read (reader); - ChildNodes.Add (tn); + ChildNodes = ChildNodes.Add (tn); } else if (reader.IsWhitespace) { reader.ReadAndStoreWhitespace (); } else if (reader.EOF) @@ -311,19 +312,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild var n = new MSBuildXmlElement (); n.Read (reader); n.ParentNode = this; - ChildNodes.Add (n); - } - } - - internal void RemoveUnknownAttribute (string name) - { - if (unknownAttributes == null) - return; - var list = new List<UnknownAttribute> (unknownAttributes); - int i = list.FindIndex (a => a.LocalName == name); - if (i != -1) { - list.RemoveAt (i); - unknownAttributes = list.ToArray (); + ChildNodes = ChildNodes.Add (n); } } @@ -342,17 +331,18 @@ namespace MonoDevelop.Projects.Formats.MSBuild internal abstract string GetElementName (); - internal virtual List<MSBuildNode> ChildNodes { + internal virtual ImmutableList<MSBuildNode> ChildNodes { get { - if (children == null) - children = new List<MSBuildNode> (); return children; } + set { + children = value; + } } internal override IEnumerable<MSBuildNode> GetChildren () { - return children != null ? children : Enumerable.Empty<MSBuildNode> (); + return children; } internal void ResetIndent (bool closeInNewLine) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs index 5743c14722..7dcb4bef45 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs @@ -46,6 +46,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild MSBuildProjectInstance mainProjectInstance; int changeStamp; bool hadXmlDeclaration; + bool isShared; MSBuildEngineManager engineManager; bool engineManagerIsLocal; @@ -74,7 +75,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public FilePath FileName { get { return file; } - set { file = value; } + set { AssertCanModify (); file = value; } } public FilePath BaseDirectory @@ -140,6 +141,30 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } + internal override void AssertCanModify () + { + if (isShared) + Runtime.AssertMainThread (); + } + + /// <summary> + /// Gets a value indicating whether this instance is shared. + /// </summary> + /// <remarks>Shared objects can only be modified in the main thread</remarks> + public bool IsShared { + get { return isShared; } + } + + /// <summary> + /// Sets this object as shared, which means that it is accessible from several threads for reading, + /// but it can only be modified in the main thread + /// </summary> + public void SetShared () + { + isShared = true; + } + + void EnableChangeTracking () { } @@ -176,6 +201,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild internal void Load (string file, MSBuildXmlReader reader) { + AssertCanModify (); try { this.file = file; IsNewProject = false; @@ -199,6 +225,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild internal void LoadXml (string xml, MSBuildXmlReader reader) { + AssertCanModify (); try { DisableChangeTracking (); var xr = new XmlTextReader (new StringReader (xml)); @@ -215,8 +242,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild void LoadFromXml (MSBuildXmlReader reader) { + AssertCanModify (); DisposeMainInstance (); - ChildNodes.Clear (); + ChildNodes = ChildNodes.Clear (); bestGroups = null; hadXmlDeclaration = false; initialWhitespace = null; @@ -292,7 +320,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (ob != null) { ob.ParentNode = this; ob.Read (reader); - ChildNodes.Add (ob); + ChildNodes = ChildNodes.Add (ob); } else base.ReadChildElement (reader); } @@ -452,7 +480,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public string DefaultTargets { get { return defaultTargets; } - set { defaultTargets = value; NotifyChanged (); } + set { AssertCanModify (); defaultTargets = value; NotifyChanged (); } } string toolsVersion; @@ -462,6 +490,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild get { return toolsVersion; } set { + AssertCanModify (); toolsVersion = value; NotifyChanged (); } @@ -500,6 +529,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public MSBuildImport AddNewImport (string name, string condition = null, MSBuildObject beforeObject = null) { + AssertCanModify (); var import = new MSBuildImport { Project = name, Condition = condition @@ -513,12 +543,14 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (index != -1) index++; } + + import.ParentNode = this; + if (index != -1) - ChildNodes.Insert (index, import); + ChildNodes = ChildNodes.Insert (index, import); else - ChildNodes.Add (import); + ChildNodes = ChildNodes.Add (import); - import.ParentNode = this; import.ResetIndent (false); NotifyChanged (); return import; @@ -531,22 +563,24 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveImport (string name, string condition = null) { + AssertCanModify (); var i = GetImport (name, condition); if (i != null) { i.RemoveIndent (); - ChildNodes.Remove (i); + ChildNodes = ChildNodes.Remove (i); NotifyChanged (); } } public void RemoveImport (MSBuildImport import) { + AssertCanModify (); if (import.ParentProject != this) throw new InvalidOperationException ("Import object does not belong to this project"); if (import.ParentObject == this) { import.RemoveIndent (); - ChildNodes.Remove (import); + ChildNodes = ChildNodes.Remove (import); NotifyChanged (); } else ((MSBuildImportGroup)import.ParentObject).RemoveImport (import); @@ -595,20 +629,23 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void AddPropertyGroup (MSBuildPropertyGroup group, bool insertAtEnd) { + AssertCanModify (); if (group.ParentProject != null) throw new InvalidOperationException ("Group already belongs to a project"); + group.ParentNode = this; + bool added = false; if (insertAtEnd) { var last = ChildNodes.FindLastIndex (g => g is MSBuildPropertyGroup); if (last != -1) { - ChildNodes.Insert (last + 1, group); + ChildNodes = ChildNodes.Insert (last + 1, group); added = true; } } else { var first = ChildNodes.FindIndex (g => g is MSBuildPropertyGroup); if (first != -1) { - ChildNodes.Insert (first, group); + ChildNodes = ChildNodes.Insert (first, group); added = true; } } @@ -616,12 +653,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (!added) { var first = ChildNodes.FindIndex (g => g is MSBuildItemGroup); if (first != -1) - ChildNodes.Insert (first, group); + ChildNodes = ChildNodes.Insert (first, group); else - ChildNodes.Add (group); + ChildNodes = ChildNodes.Add (group); } - group.ParentNode = this; group.ResetIndent (true); NotifyChanged (); } @@ -678,6 +714,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public MSBuildItemGroup AddNewItemGroup () { + AssertCanModify (); var group = new MSBuildItemGroup (); MSBuildObject refNode = null; @@ -689,12 +726,13 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (g != null) refNode = g; } + + group.ParentNode = this; if (refNode != null) - ChildNodes.Insert (ChildNodes.IndexOf (refNode) + 1, group); + ChildNodes = ChildNodes.Insert (ChildNodes.IndexOf (refNode) + 1, group); else - ChildNodes.Add (group); + ChildNodes = ChildNodes.Add (group); - group.ParentNode = this; group.ResetIndent (true); NotifyChanged (); return group; @@ -764,11 +802,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetProjectExtension (XmlElement value) { + AssertCanModify (); var ext = (MSBuildProjectExtensions)ChildNodes.FirstOrDefault (ob => ob is MSBuildProjectExtensions); if (ext == null) { ext = new MSBuildProjectExtensions (); ext.ParentNode = this; - ChildNodes.Add (ext); + ChildNodes = ChildNodes.Add (ext); ext.ResetIndent (false); } ext.SetProjectExtension (value); @@ -777,6 +816,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetMonoDevelopProjectExtension (string section, XmlElement value) { + AssertCanModify (); var elem = GetProjectExtension ("MonoDevelop"); if (elem == null) { XmlDocument doc = new XmlDocument (); @@ -807,6 +847,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveProjectExtension (string section) { + AssertCanModify (); var ext = (MSBuildProjectExtensions)ChildNodes.FirstOrDefault (ob => ob is MSBuildProjectExtensions); if (ext != null) { ext.RemoveProjectExtension (section); @@ -817,6 +858,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveMonoDevelopProjectExtension (string section) { + AssertCanModify (); var md = GetProjectExtension ("MonoDevelop"); if (md == null) return; @@ -834,14 +876,16 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void Remove (MSBuildObject ob) { + AssertCanModify (); if (ob.ParentObject == this) { ob.RemoveIndent (); - ChildNodes.Remove (ob); + ChildNodes = ChildNodes.Remove (ob); } } public void RemoveItem (MSBuildItem item) { + AssertCanModify (); if (item.ParentGroup != null) { item.RemoveIndent (); var g = item.ParentGroup; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectExtensions.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectExtensions.cs index 9c93dd64d3..dfed253c66 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectExtensions.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectExtensions.cs @@ -72,6 +72,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetProjectExtension (XmlElement value) { + AssertCanModify (); var sr = new StringReader (value.OuterXml); var xr = new XmlTextReader (sr); xr.MoveToContent (); @@ -83,10 +84,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild int i = ChildNodes.FindIndex (n => (n is MSBuildXmlElement) && ((MSBuildXmlElement)n).Name == section); if (i == -1) - ChildNodes.Add (elem); + ChildNodes = ChildNodes.Add (elem); else { - ChildNodes.RemoveAt (i); - ChildNodes.Insert (i, elem); + ChildNodes = ChildNodes.RemoveAt (i); + ChildNodes = ChildNodes.Insert (i, elem); } elem.ParentNode = this; elem.ResetIndent (false); @@ -95,9 +96,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveProjectExtension (string section) { + AssertCanModify (); int i = ChildNodes.FindIndex (n => (n is MSBuildXmlElement) && ((MSBuildXmlElement)n).Name == section); if (i != -1) { - ChildNodes.RemoveAt (i); + ChildNodes = ChildNodes.RemoveAt (i); NotifyChanged (); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs index f9f25b388c..2b49640aac 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs @@ -209,6 +209,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (string value, bool preserveCase = false, bool mergeToMainGroup = false) { + AssertCanModify (); MergeToMainGroup = mergeToMainGroup; this.preserverCase = preserveCase; valueType = preserveCase ? MSBuildValueType.Default : MSBuildValueType.DefaultPreserveCase; @@ -230,6 +231,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false) { + AssertCanModify (); MergeToMainGroup = mergeToMainGroup; this.preserverCase = false; valueType = MSBuildValueType.Path; @@ -268,6 +270,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (object value, bool mergeToMainGroup = false) { + AssertCanModify (); if (value is bool) { if (Owner != null && Owner.UppercaseBools) SetValue ((bool)value ? "True" : "False", preserveCase: true, mergeToMainGroup: mergeToMainGroup); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs index 365eee48af..0ec4ea07bb 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs @@ -32,7 +32,8 @@ using System.Xml; using MonoDevelop.Core; using System.Xml.Linq; using Microsoft.Build.BuildEngine; - +using System.Collections.Immutable;
+
namespace MonoDevelop.Projects.Formats.MSBuild { public class MSBuildPropertyGroup: MSBuildElement, IMSBuildPropertySet, IMSBuildEvaluatedPropertyCollection @@ -43,12 +44,17 @@ namespace MonoDevelop.Projects.Formats.MSBuild { } - internal override List<MSBuildNode> ChildNodes { + internal override ImmutableList<MSBuildNode> ChildNodes { get { if (ParentNode is MSBuildItem) return ((MSBuildItem)ParentNode).ChildNodes; return base.ChildNodes; } + set { + if (ParentNode is MSBuildItem) + ((MSBuildItem)ParentNode).ChildNodes = value; + base.ChildNodes = value; + } } internal MSBuildObject PropertiesParent { @@ -67,7 +73,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild prop.ParentNode = PropertiesParent; prop.Owner = this; prop.Read (reader); - ChildNodes.Add (prop); + ChildNodes = ChildNodes.Add (prop); properties [prop.Name] = prop; // If a property is defined more than once, we only care about the last registered value } @@ -85,6 +91,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild internal void CopyFrom (MSBuildPropertyGroup other) { + AssertCanModify (); foreach (var node in other.ChildNodes) { var prop = node as MSBuildProperty; if (prop != null) { @@ -92,16 +99,16 @@ namespace MonoDevelop.Projects.Formats.MSBuild var currentPropIndex = ChildNodes.FindIndex (p => (p is MSBuildProperty) && ((MSBuildProperty)p).Name == prop.Name); if (currentPropIndex != -1) { var currentProp = (MSBuildProperty) ChildNodes [currentPropIndex]; - ChildNodes [currentPropIndex] = cp; + ChildNodes = ChildNodes.SetItem (currentPropIndex, cp); } else { - ChildNodes.Add (cp); + ChildNodes = ChildNodes.Add (cp); } properties [cp.Name] = cp; cp.ParentNode = PropertiesParent; cp.Owner = this; cp.ResetIndent (false); } else - ChildNodes.Add (node); + ChildNodes = ChildNodes.Add (node); } foreach (var prop in ChildNodes.OfType<MSBuildProperty> ().ToArray ()) { if (!other.HasProperty (prop.Name)) @@ -214,6 +221,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild MSBuildProperty AddProperty (string name, string condition = null) { + AssertCanModify (); int i = propertyOrder.IndexOf (name); int insertIndex = -1; if (i != -1) { @@ -233,9 +241,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild properties [name] = prop; if (insertIndex != -1) - ChildNodes.Insert (insertIndex, prop); + ChildNodes = ChildNodes.Insert (insertIndex, prop); else - ChildNodes.Add (prop); + ChildNodes = ChildNodes.Add (prop); if (condition != null) prop.Condition = condition; @@ -272,6 +280,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool mergeToMainGroup = false, string condition = null) { + AssertCanModify (); if (value == null && defaultValue == "") value = ""; var prop = GetProperty (name, condition); @@ -295,6 +304,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null) { + AssertCanModify (); var prop = GetProperty (name, condition); var isDefault = value.CanonicalPath == defaultValue.CanonicalPath; if (isDefault && !mergeToMainGroup) { @@ -316,6 +326,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetValue (string name, object value, object defaultValue = null, bool mergeToMainGroup = false, string condition = null) { + AssertCanModify (); var prop = GetProperty (name, condition); var isDefault = object.Equals (value, defaultValue); if (isDefault && !mergeToMainGroup) { @@ -347,21 +358,24 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveProperty (MSBuildProperty prop) { + AssertCanModify (); prop.RemoveIndent (); properties.Remove (prop.Name); - ChildNodes.Remove (prop); + ChildNodes = ChildNodes.Remove (prop); NotifyChanged (); } public void RemoveAllProperties () { + AssertCanModify (); properties.Clear (); - ChildNodes.Clear (); + ChildNodes = ChildNodes.Clear (); NotifyChanged (); } public void UnMerge (IMSBuildPropertySet baseGrp, ISet<string> propsToExclude) { + AssertCanModify (); HashSet<string> baseProps = new HashSet<string> (); foreach (MSBuildProperty prop in baseGrp.GetProperties ()) { if (propsToExclude != null && propsToExclude.Contains (prop.Name)) @@ -398,6 +412,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void SetPropertyOrder (params string[] propertyNames) { + AssertCanModify (); int i = 0; foreach (var name in propertyNames) { if (i < propertyOrder.Count) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildTarget.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildTarget.cs index 269086c445..8405304be5 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildTarget.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildTarget.cs @@ -62,6 +62,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.afterTargets; } set { + AssertCanModify (); this.afterTargets = value; NotifyChanged (); } @@ -72,6 +73,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.inputs; } set { + AssertCanModify (); this.inputs = value; NotifyChanged (); } @@ -82,6 +84,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.outputs; } set { + AssertCanModify (); this.outputs = value; NotifyChanged (); } @@ -92,6 +95,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.beforeTargets; } set { + AssertCanModify (); this.beforeTargets = value; NotifyChanged (); } @@ -103,6 +107,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.dependsOnTargets; } set { + AssertCanModify (); this.dependsOnTargets = value; NotifyChanged (); } @@ -113,6 +118,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.returns; } set { + AssertCanModify (); this.returns = value; NotifyChanged (); } @@ -123,6 +129,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild return this.keepDuplicateOutputs; } set { + AssertCanModify (); this.keepDuplicateOutputs = value; NotifyChanged (); } @@ -173,14 +180,14 @@ namespace MonoDevelop.Projects.Formats.MSBuild if (ob != null) { ob.ParentNode = this; ob.Read (reader); - ChildNodes.Add (ob); + ChildNodes = ChildNodes.Add (ob); return; } var task = new MSBuildTask (); task.ParentNode = this; task.Read (reader); - ChildNodes.Add (task); + ChildNodes = ChildNodes.Add (task); } internal override void Write (XmlWriter writer, WriteContext context) @@ -195,7 +202,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild public MSBuildTarget (string name, IEnumerable<MSBuildTask> tasks) { this.name = name; - ChildNodes.AddRange (tasks); + ChildNodes = ChildNodes.AddRange (tasks); } public string Name { @@ -210,10 +217,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void RemoveTask (MSBuildTask task) { + AssertCanModify (); if (task.ParentObject != this) throw new InvalidOperationException ("Task doesn't belong to the target"); task.RemoveIndent (); - ChildNodes.Remove (task); + ChildNodes = ChildNodes.Remove (task); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildXmlNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildXmlNode.cs index b146ee7f56..89db16f5a0 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildXmlNode.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildXmlNode.cs @@ -51,6 +51,13 @@ namespace MonoDevelop.Projects.Formats.MSBuild { } + internal virtual void AssertCanModify () + { + var pp = ParentProject; + if (pp != null) + pp.AssertCanModify (); + } + internal MSBuildNode ParentNode { get { return parentObject; |