Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

276 lines
6.6 KiB
C#

//
// GroupingCollection.cs: Represents group of BuildItemGroup,
// BuildPropertyGroup and BuildChoose.
//
// Authors:
// Marek Sieradzki (marek.sieradzki@gmail.com)
// Marek Safar (marek.safar@gmail.com)
//
// (C) 2005 Marek Sieradzki
// Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.Build.BuildEngine {
internal class GroupingCollection : IEnumerable {
int imports;
int itemGroups;
Project project;
int propertyGroups;
int chooses;
LinkedList <object> list;
LinkedListNode <object> add_iterator;
public GroupingCollection (Project project)
{
list = new LinkedList <object> ();
add_iterator = null;
this.project = project;
}
public IEnumerator GetChooseEnumerator ()
{
foreach (object o in list)
if (o is BuildChoose)
yield return o;
}
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
public IEnumerator GetImportEnumerator ()
{
foreach (object o in list)
if (o is Import)
yield return o;
}
public IEnumerator GetItemGroupAndChooseEnumerator ()
{
foreach (object o in list)
if (o is BuildItemGroup || o is BuildPropertyGroup)
yield return o;
}
public IEnumerator GetItemGroupEnumerator ()
{
foreach (object o in list)
if (o is BuildItemGroup)
yield return o;
}
public IEnumerator GetPropertyGroupAndChooseEnumerator ()
{
foreach (object o in list)
if (o is BuildPropertyGroup || o is BuildChoose)
yield return o;
}
public IEnumerator GetPropertyGroupEnumerator ()
{
foreach (object o in list)
if (o is BuildPropertyGroup)
yield return o;
}
internal void Add (BuildPropertyGroup bpg)
{
bpg.GroupingCollection = this;
propertyGroups++;
if (add_iterator == null)
list.AddLast (bpg);
else {
list.AddAfter (add_iterator, bpg);
add_iterator = add_iterator.Next;
}
}
internal void Add (BuildItemGroup big)
{
itemGroups++;
if (add_iterator == null)
list.AddLast (big);
else {
list.AddAfter (add_iterator, big);
add_iterator = add_iterator.Next;
}
}
internal void Add (BuildChoose bc)
{
chooses++;
if (add_iterator == null)
list.AddLast (bc);
else {
list.AddAfter (add_iterator, bc);
add_iterator = add_iterator.Next;
}
}
internal void Add (Import import)
{
imports++;
if (add_iterator == null)
list.AddLast (import);
else {
list.AddAfter (add_iterator, import);
add_iterator = add_iterator.Next;
}
}
internal void Remove (BuildItemGroup big)
{
if (big.ParentProject != project)
throw new InvalidOperationException (
"The \"BuildItemGroup\" object specified does not belong to the correct \"Project\" object.");
big.Detach ();
list.Remove (big);
}
internal void Remove (BuildPropertyGroup bpg)
{
// FIXME: add bpg.Detach ();
bpg.XmlElement.ParentNode.RemoveChild (bpg.XmlElement);
list.Remove (bpg);
}
internal void Evaluate ()
{
Evaluate (EvaluationType.Property | EvaluationType.Choose);
Evaluate (EvaluationType.Item);
}
internal void Evaluate (EvaluationType type)
{
add_iterator = list.First;
for (var evaluate_iterator = list.First; evaluate_iterator != null; evaluate_iterator = evaluate_iterator.Next) {
var bpg = evaluate_iterator.Value as BuildPropertyGroup;
if (bpg != null) {
if ((type & EvaluationType.Property) != 0) {
EvaluateBuildPropertyGroup (bpg);
// if it wasn't moved by adding anything because of evaluating a Import shift it
if (add_iterator == evaluate_iterator)
add_iterator = add_iterator.Next;
}
continue;
}
var big = evaluate_iterator.Value as BuildItemGroup;
if (big != null) {
if ((type & EvaluationType.Item) != 0)
EvaluateBuildItemGroup (big);
continue;
}
var bc = evaluate_iterator.Value as BuildChoose;
if (bc != null) {
if ((type & EvaluationType.Choose) != 0)
EvaluateBuildChoose (bc);
continue;
}
// Should not be reached
}
add_iterator = null;
}
void EvaluateBuildPropertyGroup (BuildPropertyGroup bpg)
{
project.PushThisFileProperty (bpg.DefinedInFileName);
try {
if (ConditionParser.ParseAndEvaluate (bpg.Condition, project))
bpg.Evaluate ();
} finally {
project.PopThisFileProperty ();
}
}
void EvaluateBuildItemGroup (BuildItemGroup big)
{
project.PushThisFileProperty (big.DefinedInFileName);
try {
if (ConditionParser.ParseAndEvaluate (big.Condition, project))
big.Evaluate ();
} finally {
project.PopThisFileProperty ();
}
}
void EvaluateBuildChoose (BuildChoose bc)
{
project.PushThisFileProperty (bc.DefinedInFileName);
try {
bool whenUsed = false;
foreach (BuildWhen bw in bc.Whens) {
if (ConditionParser.ParseAndEvaluate (bw.Condition, project)) {
bw.Evaluate ();
whenUsed = true;
break;
}
}
if (!whenUsed && bc.Otherwise != null &&
ConditionParser.ParseAndEvaluate (bc.Otherwise.Condition, project)) {
bc.Otherwise.Evaluate ();
}
} finally {
project.PopThisFileProperty ();
}
}
internal int Imports {
get { return this.imports; }
}
internal int ItemGroups {
get { return this.itemGroups; }
}
internal int PropertyGroups {
get { return this.propertyGroups; }
}
internal int Chooses {
get { return this.chooses; }
}
}
[Flags]
enum EvaluationType {
Property = 1 << 0,
Item = 1 << 1,
Choose = 1 << 2,
Any = Property | Item | Choose
}
}