Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,384 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System.Collections.Generic;
using System.Xaml;
using System.Collections.ObjectModel;
using System.Runtime;
using System;
using System.ComponentModel;
using System.Reflection;
using System.Globalization;
using XamlBuildTask;
public sealed class AttributeData
{
static CultureInfo invariantEnglishUS = CultureInfo.ReadOnly(new CultureInfo("en-us", false));
List<AttributeParameterData> parameters;
Dictionary<string, AttributeParameterData> properties;
public XamlType Type
{
get;
set;
}
public IList<AttributeParameterData> Parameters
{
get
{
if (this.parameters == null)
{
this.parameters = new List<AttributeParameterData>();
}
return parameters;
}
}
public IDictionary<string, AttributeParameterData> Properties
{
get
{
if (properties == null)
{
properties = new Dictionary<string, AttributeParameterData>();
}
return properties;
}
}
// We get here when we are inside x:ClassAttributes or x:Property.Attributes. We expect the first element to be the Attribute SO.
internal static AttributeData LoadAttributeData(XamlReader reader, NamespaceTable namespaceTable, string rootNamespace)
{
AttributeData attributeData = null;
reader.Read();
if (reader.NodeType == XamlNodeType.StartObject)
{
attributeData = new AttributeData { Type = reader.Type };
bool readNext = false;
while (readNext || reader.Read())
{
namespaceTable.ManageNamespace(reader);
readNext = false;
if (reader.NodeType == XamlNodeType.StartMember)
{
if (reader.Member == XamlLanguage.Arguments)
{
foreach (AttributeParameterData parameterData in ReadParameters(reader.ReadSubtree(), namespaceTable, rootNamespace))
{
attributeData.Parameters.Add(parameterData);
}
readNext = true;
}
else if (!reader.Member.IsDirective)
{
KeyValuePair<string, AttributeParameterData> propertyInfo = ReadAttributeProperty(reader.ReadSubtree(), namespaceTable, rootNamespace);
attributeData.Properties.Add(propertyInfo.Key, propertyInfo.Value);
readNext = true;
}
}
}
}
return attributeData;
}
// Read the Property on the attribute.
private static KeyValuePair<string, AttributeParameterData> ReadAttributeProperty(XamlReader reader, NamespaceTable namespaceTable, string rootNamespace)
{
reader.Read();
Fx.Assert(reader.Member != null, "Member element should not be null");
XamlMember member = reader.Member;
AttributeParameterData propertyInfo = new AttributeParameterData();
if (member.Type != null && !member.Type.IsUnknown)
{
propertyInfo.Type = member.Type;
}
ReadParamInfo(reader, member.Type, namespaceTable, rootNamespace, propertyInfo);
return new KeyValuePair<string, AttributeParameterData>(member.Name, propertyInfo);
}
// Read the parameters on the Attribute. We expect the parameters to be in the order in which they are supposed to appear in the output code.
// Here we are inside x:Arguments and we expect a list of parameters.
private static IList<AttributeParameterData> ReadParameters(XamlReader reader, NamespaceTable namespaceTable, string rootNamespace)
{
IList<AttributeParameterData> parameters = new List<AttributeParameterData>();
bool readNext = false;
while (readNext || reader.Read())
{
readNext = false;
if (reader.NodeType == XamlNodeType.StartObject)
{
AttributeParameterData paramInfo = new AttributeParameterData();
ReadParamInfo(reader.ReadSubtree(), null, namespaceTable, rootNamespace, paramInfo);
parameters.Add(paramInfo);
readNext = true;
}
}
return parameters;
}
// Read the actual parameter info, i.e. the type of the paramter and its value.
// The first element could be a V or an SO.
private static void ReadParamInfo(XamlReader reader, XamlType type, NamespaceTable namespaceTable, string rootNamespace, AttributeParameterData paramInfo)
{
reader.Read();
bool readNext = false;
do
{
readNext = false;
if (reader.NodeType == XamlNodeType.StartObject && reader.Type == XamlLanguage.Array)
{
paramInfo.IsArray = true;
XamlReader xamlArrayReader = reader.ReadSubtree();
xamlArrayReader.Read();
while (readNext || xamlArrayReader.Read())
{
readNext = false;
if (xamlArrayReader.NodeType == XamlNodeType.StartMember && xamlArrayReader.Member.Name == "Type")
{
xamlArrayReader.Read();
if (xamlArrayReader.NodeType == XamlNodeType.Value)
{
XamlType arrayType = XamlBuildTaskServices.GetXamlTypeFromString(xamlArrayReader.Value as string, namespaceTable, xamlArrayReader.SchemaContext);
if (arrayType.UnderlyingType != null)
{
paramInfo.Type = xamlArrayReader.SchemaContext.GetXamlType(arrayType.UnderlyingType.MakeArrayType());
}
else
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.AttributeParameterTypeUnknown(arrayType)));
}
}
}
else if (xamlArrayReader.NodeType == XamlNodeType.StartObject)
{
AttributeParameterData arrayEntry = new AttributeParameterData();
ReadParamInfo(xamlArrayReader.ReadSubtree(), null, namespaceTable, rootNamespace, arrayEntry);
paramInfo.AddArrayContentsEntry(arrayEntry);
readNext = true;
}
}
}
else if (reader.NodeType == XamlNodeType.StartObject || reader.NodeType == XamlNodeType.Value)
{
paramInfo.IsArray = false;
string paramVal;
object paramObj = null;
XamlType paramType;
GetParamValueType(reader.ReadSubtree(), type, namespaceTable, rootNamespace, out paramVal, out paramType, out paramObj);
paramInfo.TextValue = paramVal;
paramInfo.Type = paramType;
paramInfo.Value = paramObj;
}
} while (readNext || reader.Read());
}
// Get the paramter value. If the value is enclosed inside nodes of the type, then get the parameter type as well.
// Else infer the type from the type of the property.
private static void GetParamValueType(XamlReader reader, XamlType type, NamespaceTable namespaceTable, string rootNamespace, out string paramValue, out XamlType paramType, out Object paramObj)
{
paramValue = String.Empty;
paramType = type;
paramObj = null;
while (reader.Read())
{
if (reader.NodeType == XamlNodeType.Value)
{
if (paramType != null && paramType.UnderlyingType != null)
{
if (!IsSupportedParameterType(paramType.UnderlyingType) || paramType.UnderlyingType.IsArray)
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.AttributeParamTypeNotSupported(paramType.UnderlyingType.FullName)));
}
paramValue = reader.Value as string;
if (typeof(Type).IsAssignableFrom(paramType.UnderlyingType))
{
Tuple<string, Type> result = ParseParameterValueTypeName(paramValue, rootNamespace, reader.SchemaContext, namespaceTable);
paramValue = result.Item1;
paramObj = result.Item2;
}
else
{
paramObj = ParseParameterValue(ref paramValue, paramType);
}
}
else
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.AttributeParameterTypeUnknown(reader.Value as string)));
}
}
else if (reader.NodeType == XamlNodeType.StartObject)
{
if (reader.Type == XamlLanguage.Null)
{
paramValue = null;
paramType = null;
}
else if (reader.Type == XamlLanguage.Type)
{
paramType = reader.SchemaContext.GetXamlType(typeof(Type));
}
else
{
paramType = reader.Type;
}
}
}
}
internal static bool IsSupportedParameterType(Type type)
{
if (type.IsArray)
{
return IsSupportedParameterType(type.GetElementType());
}
return type.IsEnum ||
type.IsPrimitive ||
typeof(string) == type ||
typeof(Type).IsAssignableFrom(type);
}
// Given a live value for an attribute parameter, returns the text that needs to be
// code-gened for the value.
internal static string GetParameterText(object value, XamlType paramType)
{
Type type = paramType.UnderlyingType;
if (type.IsEnum)
{
// Note: this doesn't support flags enums with multiple flags set, but neither
// does the existing Dev10 code
return type.FullName + "." + value.ToString();
}
else if (typeof(Type).IsAssignableFrom(type))
{
return ((Type)value).FullName;
}
else if (type == typeof(String))
{
return (string)value;
}
else if (type.IsPrimitive)
{
TypeConverter typeConverter = paramType.TypeConverter.ConverterInstance;
Fx.Assert(typeConverter != null, "All primitives have TypeConverters");
return (string)typeConverter.ConvertTo(null, invariantEnglishUS, value, typeof(string));
}
else
{
throw Fx.AssertAndThrow("Unexpected attribute parameter type");
}
}
// Given the text for an attribute parameter, parses it to a live value (if possible).
internal static object GetParameterValue(ref string paramValue, XamlType paramType)
{
if (typeof(Type).IsAssignableFrom(paramType.UnderlyingType))
{
// We can't convert a CLR type name to a Type because we don't know what assembly it's from
return null;
}
return ParseParameterValue(ref paramValue, paramType);
}
// Parses a XAML QName to a CLR Type Name (and the corresponding ROL type, if available)
private static Tuple<string, Type> ParseParameterValueTypeName(string paramValue, string rootNamespace, XamlSchemaContext schemaContext, NamespaceTable namespaceTable)
{
XamlType xamlType = XamlBuildTaskServices.GetXamlTypeFromString(paramValue, namespaceTable, schemaContext);
string clrTypeName;
if (!XamlBuildTaskServices.TryGetClrTypeName(xamlType, rootNamespace, out clrTypeName))
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TypeNameUnknown(XamlBuildTaskServices.GetFullTypeName(xamlType))));
}
return Tuple.Create(clrTypeName, xamlType.UnderlyingType);
}
// Given a text value for an attribute parameter, attempts to convert it to a live value.
// Inverse of GetParameterText.
private static object ParseParameterValue(ref string paramValue, XamlType paramType)
{
object valueObj = null;
paramValue = NormalizeParameterText(paramValue, paramType);
if (!paramType.UnderlyingType.Assembly.ReflectionOnly)
{
TypeConverter typeConverter = paramType.TypeConverter.ConverterInstance;
if (typeConverter != null && typeConverter.CanConvertFrom(paramValue.GetType()))
{
try
{
valueObj = typeConverter.ConvertFrom(null, invariantEnglishUS, paramValue);
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
// ----ing exceptions here to avoid throwing on
// a format that we don't recognize, but the compiler
// might be able to interpret.
}
}
}
return valueObj;
}
// Get the parameter value that is to be put in the generated code as is.
private static string NormalizeParameterText(string value, XamlType xamlType)
{
string paramValue;
Type type = xamlType.UnderlyingType;
Fx.Assert(!typeof(Type).IsAssignableFrom(type), "This method should not be called for Types");
if (type.IsEnum)
{
paramValue = type.FullName + "." + value;
}
else if (type == typeof(String))
{
paramValue = value;
}
else if (type.IsPrimitive)
{
value = value.TrimStart('"');
value = value.TrimEnd('"');
if (type == typeof(bool))
{
if (string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0)
{
paramValue = "true";
}
else if (string.Compare(value, "false", StringComparison.OrdinalIgnoreCase) == 0)
{
paramValue = "false";
}
else
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnknownBooleanValue(value)));
}
}
else
{
paramValue = value;
}
}
else
{
throw Fx.AssertAndThrow("Unexpected attribute parameter type");
}
return paramValue;
}
}
}

View File

@@ -0,0 +1,159 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System.Collections.Generic;
using System;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Xaml;
using XamlBuildTask;
// This class is modal. The following properties are set in different modes:
// Type TextValue Value ArrayContents
// x:Null
// x:Array x x
// Known Value x x x
// Unknown Value x x
//
// While this modality is not ideal, it's preferable to having multiple concrete classes
// and requiring the user to down-cast.
// However, we can't make the class mutable and expect users to maintain the modality.
// So it's publicly immutable and has constructors for various modes (except for x:Null,
// which the user can replicate by passing value == null and type == object).
public sealed class AttributeParameterData
{
List<AttributeParameterData> arrayContents;
public AttributeParameterData(XamlType type, string textValue)
{
ValidateType(type);
if (textValue == null && type.UnderlyingType.IsValueType)
{
throw FxTrace.Exception.Argument("value", SR.AttributeValueNotNullable(type.UnderlyingType));
}
this.Type = type;
if (textValue != null)
{
this.Value = AttributeData.GetParameterValue(ref textValue, type);
this.TextValue = textValue;
}
}
public AttributeParameterData(XamlType type, object value)
{
ValidateType(type);
if (value == null && type.UnderlyingType.IsValueType)
{
throw FxTrace.Exception.Argument("value", SR.AttributeValueNotNullable(type.UnderlyingType));
}
if (value != null && !type.UnderlyingType.IsAssignableFrom(value.GetType()))
{
throw FxTrace.Exception.Argument("value", SR.AttributeValueNotAssignableToType(value.GetType(), type.UnderlyingType));
}
this.Type = type;
if (value != null)
{
if (type.UnderlyingType.IsArray)
{
Array array = (Array)value;
XamlType elementType = type.SchemaContext.GetXamlType(type.UnderlyingType.GetElementType());
this.arrayContents = new List<AttributeParameterData>();
foreach (object item in array)
{
this.arrayContents.Add(new AttributeParameterData(elementType, item));
}
this.IsArray = true;
}
else
{
this.Value = value;
this.TextValue = AttributeData.GetParameterText(value, type);
}
}
}
public AttributeParameterData(XamlType type, IEnumerable<AttributeParameterData> arrayContents)
{
ValidateType(type);
if (!type.UnderlyingType.IsArray)
{
throw FxTrace.Exception.Argument("type", SR.AttributeTypeIsNotArray(type));
}
if (arrayContents == null)
{
throw FxTrace.Exception.ArgumentNull("arrayContents");
}
this.Type = type;
this.arrayContents = new List<AttributeParameterData>(arrayContents);
this.IsArray = true;
}
internal AttributeParameterData()
{
TextValue = String.Empty;
IsArray = false;
}
public string TextValue
{
get;
internal set;
}
public object Value
{
get;
internal set;
}
public XamlType Type
{
get;
internal set;
}
public ReadOnlyCollection<AttributeParameterData> ArrayContents
{
get
{
return this.arrayContents == null ? null : this.arrayContents.AsReadOnly();
}
}
internal void AddArrayContentsEntry(AttributeParameterData arrayContentsEntry)
{
if (arrayContentsEntry != null)
{
if (this.arrayContents == null)
{
this.arrayContents = new List<AttributeParameterData>();
}
this.arrayContents.Add(arrayContentsEntry);
}
}
internal bool IsArray { get; set; }
private static void ValidateType(XamlType type)
{
if (type == null)
{
throw FxTrace.Exception.ArgumentNull("type");
}
if (type.IsUnknown)
{
throw FxTrace.Exception.Argument("type", SR.AttributeParameterTypeUnknownNoErrNum(type));
}
if (!AttributeData.IsSupportedParameterType(type.UnderlyingType))
{
throw FxTrace.Exception.Argument("type", SR.AttributeParamTypeNotSupportedNoErrNum(type));
}
}
}
}

View File

@@ -0,0 +1,158 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Build.Utilities;
public class BuildExtensionContext
{
static readonly IList<string> emptyList = new List<string>(0);
List<string> references;
List<string> sourceCodeFiles;
List<string> generatedFiles;
List<string> generatedResourceFiles;
internal BuildExtensionContext()
{
}
public string AssemblyName
{
get;
internal set;
}
public bool IsInProcessXamlMarkupCompile
{
get;
internal set;
}
public string Language
{
get;
internal set;
}
public string OutputPath
{
get;
internal set;
}
public ReadOnlyCollection<string> References
{
get
{
if (this.references == null)
{
this.references = new List<string>();
}
return this.references.AsReadOnly();
}
}
public string RootNamespace
{
get;
internal set;
}
public ReadOnlyCollection<string> SourceCodeFiles
{
get
{
if (this.sourceCodeFiles == null)
{
this.sourceCodeFiles = new List<string>();
}
return this.sourceCodeFiles.AsReadOnly();
}
}
public string LocalAssembly
{
get;
internal set;
}
public TaskLoggingHelper XamlBuildLogger
{
get;
internal set;
}
public ReadOnlyCollection<string> GeneratedFiles
{
get
{
if (this.generatedFiles == null)
{
this.generatedFiles = new List<string>();
}
return this.generatedFiles.AsReadOnly();
}
}
public ReadOnlyCollection<string> GeneratedResourceFiles
{
get
{
if (this.generatedResourceFiles == null)
{
this.generatedResourceFiles = new List<string>();
}
return this.generatedResourceFiles.AsReadOnly();
}
}
public void AddGeneratedFile(string fileName)
{
if (this.generatedFiles == null)
{
this.generatedFiles = new List<string>();
}
this.generatedFiles.Add(fileName);
}
public void AddGeneratedResourceFile(string fileName)
{
if (this.generatedResourceFiles == null)
{
this.generatedResourceFiles = new List<string>();
}
this.generatedResourceFiles.Add(fileName);
}
internal void AddReferences(IList<string> references)
{
if (references != null)
{
if (this.references == null)
{
this.references = new List<string>();
}
this.references.AddRange(references);
}
}
internal void AddSourceCodeFiles(IList<string> sourceCodeFiles)
{
if (sourceCodeFiles != null)
{
if (this.sourceCodeFiles == null)
{
this.sourceCodeFiles = new List<string>();
}
this.sourceCodeFiles.AddRange(sourceCodeFiles);
}
}
}
}

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xaml.Schema;
using System.Xaml;
using System.Windows.Markup;
using System.Runtime;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Collections;
public class ClassData
{
[Fx.Tag.Queue(typeof(NamedObject), Scope = Fx.Tag.Strings.DeclaringInstance)]
private List<NamedObject> namedObjects;
[Fx.Tag.Queue(typeof(string), Scope = Fx.Tag.Strings.DeclaringInstance)]
private List<string> codeSnippets;
List<AttributeData> attributes;
PropertyDataCollection properties;
public ClassData()
{
this.IsPublic = true;
}
public XamlType BaseType
{
get;
set;
}
public IList<String> CodeSnippets
{
get
{
if (codeSnippets == null)
{
codeSnippets = new List<String>();
}
return codeSnippets;
}
}
public string EmbeddedResourceFileName
{
get;
internal set;
}
public KeyedCollection<string, PropertyData> Properties
{
get
{
if (this.properties == null)
{
this.properties = new PropertyDataCollection();
}
return this.properties;
}
}
public IList<AttributeData> Attributes
{
get
{
if (attributes == null)
{
attributes = new List<AttributeData>();
}
return attributes;
}
}
public string Name
{
get;
internal set;
}
public IList<NamedObject> NamedObjects
{
get
{
if (namedObjects == null)
{
namedObjects = new List<NamedObject>();
}
return namedObjects;
}
}
public String Namespace
{
get;
internal set;
}
public XamlNodeList EmbeddedResourceXaml
{
get;
set;
}
public bool IsPublic
{
get;
set;
}
public string FileName
{
get;
internal set;
}
public string HelperClassFullName
{
get;
internal set;
}
internal String RootNamespace
{
get;
set;
}
internal bool SourceFileExists
{
get;
set;
}
internal bool RequiresCompilationPass2
{
get;
set;
}
class PropertyDataCollection : KeyedCollection<string, PropertyData>
{
protected override string GetKeyForItem(PropertyData item)
{
return item.Name;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System.Collections.Generic;
using System.Diagnostics;
using System.Xaml;
using System.Runtime;
using System.Reflection;
using System;
using System.Xaml.Schema;
using Microsoft.Build.Utilities;
using XamlBuildTask;
class ClassValidator
{
string xamlFileName;
IList<LogData> eventArgs;
Assembly localAssembly;
string rootNamespace;
public ClassValidator(string xamlFileName, Assembly localAssembly, string rootNamespace)
{
this.xamlFileName = xamlFileName;
this.localAssembly = localAssembly;
this.eventArgs = null;
this.rootNamespace = rootNamespace;
}
public bool ValidateXaml(XamlReader xamlReader, bool failOnFirstError, string assemblyName, out IList<LogData> validationErrors)
{
if (xamlReader == null)
{
throw FxTrace.Exception.ArgumentNull("xamlReader");
}
validationErrors = null;
// We loop through the provided XAML using a XamlValidatingReader to ensure that:
// 1. XAML is valid.
// 2. All types referenced in XAML are validate-able. At this point, any types defined in the local
// assembly should be referenced, so this should be possible.
XamlValidatingReader reader = new XamlValidatingReader(xamlReader, this.localAssembly, rootNamespace, assemblyName);
reader.OnValidationError += new EventHandler<ValidationEventArgs>(reader_OnValidationError);
while (reader.Read())
{
if (this.eventArgs != null && failOnFirstError)
{
validationErrors = this.eventArgs;
return false;
}
}
validationErrors = this.eventArgs;
if (validationErrors != null && validationErrors.Count > 0)
{
return false;
}
return true;
}
void reader_OnValidationError(object sender, ValidationEventArgs e)
{
if (this.eventArgs == null)
{
this.eventArgs = new List<LogData>();
}
this.eventArgs.Add(new LogData()
{
FileName = this.xamlFileName,
LineNumber = e.LineNumber,
LinePosition = e.LinePosition,
Message = e.Message
});
}
}
}

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.CodeDom;
static class CodeDomExtensionMethods
{
internal static CodeVariableReferenceExpression DeclareVar(this CodeStatementCollection block, Type type,
string name, CodeExpression initExpression)
{
block.Add(new CodeVariableDeclarationStatement()
{
Name = name,
Type = new CodeTypeReference(type),
InitExpression = initExpression
});
return new CodeVariableReferenceExpression(name);
}
internal static CodeFieldReferenceExpression Field(this CodeExpression targetObject, string fieldName)
{
return new CodeFieldReferenceExpression(targetObject, fieldName);
}
internal static CodeMethodInvokeExpression Invoke(this CodeExpression targetObject, string methodName,
params CodeExpression[] parameters)
{
return new CodeMethodInvokeExpression(targetObject, methodName, parameters);
}
internal static CodeObjectCreateExpression New(this Type type, params CodeExpression[] parameters)
{
return new CodeObjectCreateExpression(type, parameters);
}
internal static CodePropertyReferenceExpression Property(this CodeExpression targetObject, string propertyName)
{
return new CodePropertyReferenceExpression(targetObject, propertyName);
}
}
}

View File

@@ -0,0 +1,315 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using XamlBuildTask;
[Fx.Tag.XamlVisible(true)]
public class CompilationPass2Task : Task
{
List<ITaskItem> generatedCodeFiles = new List<ITaskItem>();
// We will do Dev10 behavior if NONE of the new required properties are specified. This can happen
// if a Dev10 version of the Microsoft.Xaml.Targets file is being used with Dev11 installed.
// The new required properties for Dev11 are:
// Language
// OutputPath
// MSBuildProjectDirectory
// ApplicationMarkupWithTypeName
//
// If ANY of these are specified, then ALL must be specified.
bool supportExtensions = false;
string language;
string outputPath;
string msBuildProjectDirectory;
ITaskItem[] applicationMarkupWithTypeName;
public CompilationPass2Task()
{
}
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] ApplicationMarkup { get; set; }
public string AssemblyName
{ get; set; }
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] References { get; set; }
// Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
public string Language
{
get
{
return this.language;
}
set
{
this.language = value;
this.supportExtensions = true;
}
}
// Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
public string OutputPath
{
get
{
return this.outputPath;
}
set
{
this.outputPath = value;
this.supportExtensions = true;
}
}
// Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
public string MSBuildProjectDirectory
{
get
{
return this.msBuildProjectDirectory;
}
set
{
this.msBuildProjectDirectory = value;
this.supportExtensions = true;
}
}
public bool IsInProcessXamlMarkupCompile
{ get; set; }
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] SourceCodeFiles
{ get; set; }
public ITaskItem[] XamlBuildTypeInspectionExtensionNames
{ get; set; }
// Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
public ITaskItem[] ApplicationMarkupWithTypeName
{
get
{
return this.applicationMarkupWithTypeName;
}
set
{
this.applicationMarkupWithTypeName = value;
this.supportExtensions = true;
}
}
public string LocalAssemblyReference
{ get; set; }
public string RootNamespace
{ get; set; }
public string BuildTaskPath
{ get; set; }
[Output]
public ITaskItem[] ExtensionGeneratedCodeFiles
{
get
{
return generatedCodeFiles.ToArray();
}
set
{
generatedCodeFiles = new List<ITaskItem>(value);
}
}
public override bool Execute()
{
AppDomain appDomain = null;
try
{
ValidateRequiredDev11Properties();
appDomain = XamlBuildTaskServices.CreateAppDomain("CompilationPass2AppDomain_" + Guid.NewGuid(), BuildTaskPath);
CompilationPass2TaskInternal wrapper = (CompilationPass2TaskInternal)appDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof(CompilationPass2TaskInternal).FullName);
PopulateBuildArtifacts(wrapper);
bool ret = wrapper.Execute();
ExtractBuiltArtifacts(wrapper);
if (!ret)
{
foreach (LogData logData in wrapper.LogData)
{
XamlBuildTaskServices.LogException(
this.Log,
logData.Message,
logData.FileName,
logData.LineNumber,
logData.LinePosition);
}
}
return ret;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
XamlBuildTaskServices.LogException(this.Log, e.Message);
return false;
}
finally
{
if (appDomain != null)
{
AppDomain.Unload(appDomain);
}
}
}
string SeparateWithComma(string originalString, string stringToAppend)
{
if (!String.IsNullOrEmpty(originalString))
{
return String.Join(", ", originalString, stringToAppend);
}
else
{
return stringToAppend;
}
}
void ValidateRequiredDev11Properties()
{
if (this.supportExtensions)
{
string requiredPropertiesNotSpecified = "";
if (this.language == null)
{
requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "Language");
}
if (this.outputPath == null)
{
requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "OutputPath");
}
if (this.msBuildProjectDirectory == null)
{
requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "MSBuildProjectDirectory");
}
if (this.applicationMarkupWithTypeName == null)
{
requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "ApplicationMarkupWithTypeName");
}
if (!String.IsNullOrEmpty(requiredPropertiesNotSpecified))
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.MissingRequiredParametersCompilationPass2Task(requiredPropertiesNotSpecified)));
}
}
}
void PopulateBuildArtifacts(CompilationPass2TaskInternal wrapper)
{
if (!this.supportExtensions)
{
IList<string> applicationMarkup = new List<string>(this.ApplicationMarkup.Length);
foreach (ITaskItem taskItem in this.ApplicationMarkup)
{
applicationMarkup.Add(taskItem.ItemSpec);
}
wrapper.ApplicationMarkup = applicationMarkup;
}
wrapper.SupportExtensions = this.supportExtensions;
wrapper.BuildLogger = this.Log;
wrapper.References = this.References
.Select(i => new DelegatingTaskItem(i) as ITaskItem).ToList();
wrapper.LocalAssemblyReference = this.LocalAssemblyReference;
wrapper.AssemblyName = this.AssemblyName;
wrapper.RootNamespace = this.RootNamespace;
wrapper.Language = this.Language;
wrapper.OutputPath = this.OutputPath;
wrapper.IsInProcessXamlMarkupCompile = this.IsInProcessXamlMarkupCompile;
wrapper.MSBuildProjectDirectory = this.MSBuildProjectDirectory;
IList<string> sourceCodeFiles = null;
if (this.SourceCodeFiles != null)
{
sourceCodeFiles = new List<string>(this.SourceCodeFiles.Length);
foreach (ITaskItem taskItem in this.SourceCodeFiles)
{
sourceCodeFiles.Add(taskItem.ItemSpec);
}
}
wrapper.SourceCodeFiles = sourceCodeFiles;
if (this.supportExtensions)
{
wrapper.XamlBuildTaskTypeInspectionExtensionNames = XamlBuildTaskServices.GetXamlBuildTaskExtensionNames(this.XamlBuildTypeInspectionExtensionNames);
// Here we create a Dictionary of Type Full Name and corresponding TaskItem
// This is passed to the extensions which enables them to look up
// metadata about a type like file name.
IDictionary<string, ITaskItem> applicationMarkupWithTypeName = null;
if (this.ApplicationMarkupWithTypeName != null)
{
applicationMarkupWithTypeName = new Dictionary<string, ITaskItem>();
}
foreach (ITaskItem taskItem in this.ApplicationMarkupWithTypeName)
{
string typeName = taskItem.GetMetadata("typeName");
if (!String.IsNullOrWhiteSpace(typeName))
{
applicationMarkupWithTypeName.Add(typeName, new DelegatingTaskItem(taskItem));
}
}
wrapper.ApplicationMarkupWithTypeName = applicationMarkupWithTypeName;
}
}
void ExtractBuiltArtifacts(CompilationPass2TaskInternal wrapper)
{
if (wrapper.GeneratedCodeFiles == null)
{
return;
}
foreach (string code in wrapper.GeneratedCodeFiles)
{
this.generatedCodeFiles.Add(new TaskItem(code));
}
}
}
}

View File

@@ -0,0 +1,353 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Xaml;
using System.Xaml.Schema;
using System.Xml;
using System.Reflection;
using System.Runtime;
using System.Globalization;
using Microsoft.Build.Utilities;
using XamlBuildTask;
using Microsoft.Build.Framework;
internal class CompilationPass2TaskInternal : MarshalByRefObject
{
IList<string> applicationMarkup;
IList<ITaskItem> references;
IList<LogData> logData;
IList<string> sourceCodeFiles;
IList<string> generatedCodeFiles;
XamlBuildTypeInspectionExtensionContext buildContextForExtensions;
IDictionary<string, ITaskItem> applicationMarkupWithTypeName;
public IList<string> ApplicationMarkup
{
get
{
if (this.applicationMarkup == null)
{
this.applicationMarkup = new List<string>();
}
return this.applicationMarkup;
}
set
{
this.applicationMarkup = value;
}
}
public string AssemblyName
{ get; set; }
public TaskLoggingHelper BuildLogger
{ get; set; }
public string LocalAssemblyReference
{ get; set; }
public string RootNamespace
{ get; set; }
public string MSBuildProjectDirectory
{ get; set; }
public IList<LogData> LogData
{
get
{
if (this.logData == null)
{
this.logData = new List<LogData>();
}
return this.logData;
}
}
public IList<ITaskItem> References
{
get
{
if (this.references == null)
{
this.references = new List<ITaskItem>();
}
return this.references;
}
set
{
this.references = value;
}
}
public IList<string> SourceCodeFiles
{
get
{
if (this.sourceCodeFiles == null)
{
this.sourceCodeFiles = new List<string>();
}
return this.sourceCodeFiles;
}
set
{
this.sourceCodeFiles = value;
}
}
public IList<string> GeneratedCodeFiles
{
get
{
if (this.generatedCodeFiles == null)
{
this.generatedCodeFiles = new List<string>();
}
return generatedCodeFiles;
}
}
public IDictionary<string, ITaskItem> ApplicationMarkupWithTypeName
{
get
{
if (this.applicationMarkupWithTypeName == null)
{
this.applicationMarkupWithTypeName = new Dictionary<string, ITaskItem>();
}
return applicationMarkupWithTypeName;
}
set
{
this.applicationMarkupWithTypeName = value;
}
}
public string OutputPath
{ get; set; }
public string Language
{ get; set; }
public bool IsInProcessXamlMarkupCompile
{ get; set; }
public IList<Tuple<string, string, string>> XamlBuildTaskTypeInspectionExtensionNames
{ get; set; }
public IList<Tuple<AssemblyName, Assembly>> ReferencedAssemblies
{ get; set; }
public bool SupportExtensions
{ get; set; }
public XamlBuildTypeInspectionExtensionContext BuildContextForExtensions
{
get
{
if (this.buildContextForExtensions == null)
{
XamlBuildTypeInspectionExtensionContext local = new XamlBuildTypeInspectionExtensionContext();
local.AssemblyName = this.AssemblyName;
local.IsInProcessXamlMarkupCompile = this.IsInProcessXamlMarkupCompile;
local.Language = this.Language;
local.OutputPath = this.OutputPath;
local.RootNamespace = this.RootNamespace;
local.AddSourceCodeFiles(this.SourceCodeFiles);
local.LocalAssembly = this.LocalAssemblyReference;
local.XamlBuildLogger = this.BuildLogger;
local.AddReferences(XamlBuildTaskServices.GetReferences(this.references));
local.AddApplicationMarkupWithTypeName(this.ApplicationMarkupWithTypeName);
this.buildContextForExtensions = local;
}
return this.buildContextForExtensions;
}
}
public bool Execute()
{
try
{
if ((!this.SupportExtensions) && ((this.ApplicationMarkup == null) || this.ApplicationMarkup.Count == 0))
{
return true;
}
else if (this.ApplicationMarkupWithTypeName == null || this.ApplicationMarkupWithTypeName.Count == 0)
{
return true;
}
IList<Assembly> loadedAssemblyList = null;
if (this.References != null)
{
loadedAssemblyList = XamlBuildTaskServices.Load(this.References, false);
}
Assembly localAssembly = null;
if (LocalAssemblyReference != null)
{
try
{
localAssembly = XamlBuildTaskServices.Load(LocalAssemblyReference);
loadedAssemblyList.Add(localAssembly);
}
catch (FileNotFoundException e)
{
XamlBuildTaskServices.LogException(this.BuildLogger, e.Message, e.FileName, 0, 0);
return false;
}
}
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(XamlBuildTaskServices.ReflectionOnlyAssemblyResolve);
XamlNsReplacingContext wxsc = new XamlNsReplacingContext(loadedAssemblyList, localAssembly.GetName().Name, this.AssemblyName);
bool foundValidationErrors = false;
if (!this.SupportExtensions)
{
foreach (string app in ApplicationMarkup)
{
try
{
if (!ProcessMarkupItem(app, wxsc, localAssembly))
{
foundValidationErrors = true;
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
XamlBuildTaskServices.LogException(this.BuildLogger, e.Message, app, 0, 0);
return false;
}
}
}
else
{
foreach (ITaskItem app in this.ApplicationMarkupWithTypeName.Values)
{
string inputMarkupFile = app.ItemSpec;
try
{
if (!ProcessMarkupItem(inputMarkupFile, wxsc, localAssembly))
{
foundValidationErrors = true;
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
XamlBuildTaskServices.LogException(this.BuildLogger, e.Message, inputMarkupFile, 0, 0);
return false;
}
}
if (!foundValidationErrors)
{
foundValidationErrors = !ExecuteExtensions();
if (!foundValidationErrors)
{
foundValidationErrors = this.BuildLogger.HasLoggedErrors;
}
}
}
return !foundValidationErrors;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
// Log unknown errors that do not originate from the task.
// Assumes that all known errors are logged when the exception is thrown.
XamlBuildTaskServices.LogException(this.BuildLogger, e.Message);
return false;
}
}
bool ProcessMarkupItem(string markupItem, XamlNsReplacingContext wxsc, Assembly localAssembly)
{
XamlXmlReaderSettings settings = new XamlXmlReaderSettings() { LocalAssembly = localAssembly, ProvideLineInfo = true, AllowProtectedMembersOnRoot = true };
using (StreamReader streamReader = new StreamReader(markupItem))
{
var xamlReader = new XamlXmlReader(XmlReader.Create(streamReader), wxsc, settings);
ClassValidator validator = new ClassValidator(markupItem, localAssembly, this.RootNamespace);
IList<LogData> validationErrors = null;
if (validator.ValidateXaml(xamlReader, false, this.AssemblyName, out validationErrors))
{
return true;
}
else
{
foreach (LogData logData in validationErrors)
{
this.LogData.Add(logData);
}
return false;
}
}
}
bool ExecuteExtensions()
{
ResolveAssemblyHelper resolveAssemblyHelper = new ResolveAssemblyHelper(XamlBuildTaskServices.GetReferences(this.References));
AppDomain.CurrentDomain.AssemblyResolve += resolveAssemblyHelper.ResolveLocalProjectReferences;
bool extensionExecutedSuccessfully = true;
try
{
IEnumerable<IXamlBuildTypeInspectionExtension> extensions =
XamlBuildTaskServices.GetXamlBuildTaskExtensions<IXamlBuildTypeInspectionExtension>(
this.XamlBuildTaskTypeInspectionExtensionNames,
this.BuildLogger,
this.MSBuildProjectDirectory);
foreach (IXamlBuildTypeInspectionExtension extension in extensions)
{
try
{
extensionExecutedSuccessfully &= extension.Execute(this.BuildContextForExtensions);
}
catch (FileNotFoundException e)
{
throw FxTrace.Exception.AsError(new LoggableException(SR.ExceptionThrownInExtension(extension.ToString(), e.GetType().ToString(), SR.AssemblyNotFound(ResolveAssemblyHelper.FileNotFound))));
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
throw FxTrace.Exception.AsError(new LoggableException(SR.ExceptionThrownInExtension(extension.ToString(), e.GetType().ToString(), e.Message)));
}
}
if (!this.BuildLogger.HasLoggedErrors && extensionExecutedSuccessfully)
{
foreach (string file in this.BuildContextForExtensions.GeneratedFiles)
{
this.GeneratedCodeFiles.Add(file);
}
}
}
finally
{
AppDomain.CurrentDomain.AssemblyResolve -= resolveAssemblyHelper.ResolveLocalProjectReferences;
}
return extensionExecutedSuccessfully;
}
}
}

View File

@@ -0,0 +1,72 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections;
using Microsoft.Build.Framework;
// In Dev10, we allowed use of non-remotable ITaskItems. While there's not really any good scenario
// for those, we need to support that for back-compat. So we wrap each provided TaskItems in an MBRO.
internal class DelegatingTaskItem : MarshalByRefObject, ITaskItem
{
private ITaskItem underlyingItem;
// This is different from TaskItem.ctor(ITaskItem): it's a wrapper, not a clone.
// So any changes are propagated back to the original object.
public DelegatingTaskItem(ITaskItem underlyingItem)
{
this.underlyingItem = underlyingItem;
}
public string ItemSpec
{
get
{
return this.underlyingItem.ItemSpec;
}
set
{
this.underlyingItem.ItemSpec = value;
}
}
public int MetadataCount
{
get { return this.underlyingItem.MetadataCount; }
}
public ICollection MetadataNames
{
get { return this.underlyingItem.MetadataNames; }
}
public IDictionary CloneCustomMetadata()
{
return this.underlyingItem.CloneCustomMetadata();
}
public void CopyMetadataTo(ITaskItem destinationItem)
{
this.underlyingItem.CopyMetadataTo(destinationItem);
}
public string GetMetadata(string metadataName)
{
return this.underlyingItem.GetMetadata(metadataName);
}
public void RemoveMetadata(string metadataName)
{
this.underlyingItem.RemoveMetadata(metadataName);
}
public void SetMetadata(string metadataName, string metadataValue)
{
this.underlyingItem.SetMetadata(metadataName, metadataValue);
}
}
}

View File

@@ -0,0 +1,235 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xaml;
using System.Xaml.Schema;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Reflection;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using Microsoft.Build.BuildEngine;
[Fx.Tag.XamlVisible(true)]
public class GenerateTemporaryAssemblyTask : Task
{
const string MSBuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003";
// We will do Dev10 behavior if the new required property GeneratedResourceFiles is NOT specified. This can happen
// if a Dev10 version of the Microsoft.Xaml.Targets file is being used with Dev11 installed.
bool supportExtensions = false;
ITaskItem[] generatedResourceFiles;
public GenerateTemporaryAssemblyTask()
{
}
[Required]
public string AssemblyName
{ get; set; }
[Required]
public string OutputPath
{ get; set; }
[Required]
public string CurrentProject
{ get; set; }
[Fx.Tag.KnownXamlExternal]
[Required]
public ITaskItem[] SourceCodeFiles { get; set; }
[Required]
public string CompileTargetName
{ get; set; }
// Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
public ITaskItem[] GeneratedResourcesFiles
{
get
{
return this.generatedResourceFiles;
}
set
{
this.generatedResourceFiles = value;
this.supportExtensions = true;
}
}
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] ReferencePaths
{ get; set; }
[Required]
public string ApplicationMarkupTypeName
{ get; set; }
public override bool Execute()
{
bool retVal;
try
{
XDocument projectDocument = XDocument.Load(this.CurrentProject);
if (projectDocument != null)
{
XElement projectElement = projectDocument.Element(XName.Get("Project", MSBuildNamespace));
if (projectElement != null)
{
RemoveItemsByName(projectElement, this.ApplicationMarkupTypeName);
RemoveItemsByName(projectElement, "Reference");
RemoveItemsByName(projectElement, "ProjectReference");
if (this.supportExtensions)
{
AddNewResourceItems(projectElement, this.GeneratedResourcesFiles);
}
AddNewItems(projectElement, "Compile", this.SourceCodeFiles);
AddNewItems(projectElement, "ReferencePath", this.ReferencePaths);
RemovePropertyByName(projectElement, "OutputType");
RemovePropertyByName(projectElement, "AssemblyName");
AddNewProperties(projectElement,
new ProjectProperty[] {
new ProjectProperty() { Name = "OutputType", Value = "Library" },
new ProjectProperty() { Name = "AssemblyName", Value = this.AssemblyName },
new ProjectProperty() { Name = "Utf8Output", Value = "true", Condition = "'$(Utf8Output)' == ''" }
});
}
}
string randomName = Path.GetRandomFileName();
randomName = Path.ChangeExtension(randomName, "");
string filename = Path.ChangeExtension(randomName, ".tmp_proj");
projectDocument.Save(filename);
Hashtable globalProperties = new Hashtable();
globalProperties["IntermediateOutputPath"] = this.OutputPath;
globalProperties["AssemblyName"] = this.AssemblyName;
globalProperties["OutputType"] = "Library";
retVal = base.BuildEngine.BuildProjectFile(filename, new string[] { this.CompileTargetName }, globalProperties, null);
File.Delete(filename);
return retVal;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
// Log unknown errors that do not originate from the task.
// Assumes that all known errors are logged when the exception is thrown.
XamlBuildTaskServices.LogException(this.Log, e.Message);
retVal = false;
}
return retVal;
}
void RemoveItemsByName(XElement project, string itemName)
{
if (!string.IsNullOrEmpty(itemName))
{
IEnumerable<XElement> itemGroups = project.Elements(XName.Get("ItemGroup", MSBuildNamespace));
itemGroups.Elements(XName.Get(itemName, MSBuildNamespace)).Remove();
}
}
void AddNewItems(XElement project, string itemName, ITaskItem[] items)
{
if (!string.IsNullOrEmpty(itemName) && items != null)
{
XElement newItemGroup = new XElement(XName.Get("ItemGroup", MSBuildNamespace));
project.Add(newItemGroup);
foreach (ITaskItem item in items)
{
XElement newElement = new XElement(XName.Get(itemName, MSBuildNamespace));
XAttribute include = new XAttribute("Include", item.ItemSpec);
newElement.Add(include);
newItemGroup.Add(newElement);
}
}
}
//<ItemGroup>
// <EmbeddedResource Include="@(XamlGeneratedResources)">
// <Type>Non-Resx</Type>
// <WithCulture>false</WithCulture>
// </EmbeddedResource>
//</ItemGroup>
void AddNewResourceItems(XElement project, ITaskItem[] items)
{
if (items != null && items.Length > 0)
{
XElement newItemGroup = new XElement(XName.Get("ItemGroup", MSBuildNamespace));
project.Add(newItemGroup);
foreach (ITaskItem item in items)
{
XElement newResource = new XElement(XName.Get("EmbeddedResource", MSBuildNamespace));
newResource.Add(new XAttribute("Include", item.ItemSpec));
XElement type = new XElement(XName.Get("Type", MSBuildNamespace), "Non-Resx");
newResource.Add(type);
XElement withCulture = new XElement(XName.Get("WithCulture", MSBuildNamespace), "false");
newResource.Add(withCulture);
newItemGroup.Add(newResource);
}
}
}
void RemovePropertyByName(XElement project, string propertyName)
{
if (!string.IsNullOrEmpty(propertyName))
{
IEnumerable<XElement> itemGroups = project.Elements(XName.Get("PropertyGroup", MSBuildNamespace));
itemGroups.Elements(XName.Get(propertyName, MSBuildNamespace)).Remove();
}
}
void AddNewProperties(XElement project, IEnumerable<ProjectProperty> properties)
{
if (properties != null)
{
XElement newPropertyGroup = new XElement(XName.Get("PropertyGroup", MSBuildNamespace));
project.Add(newPropertyGroup);
foreach (ProjectProperty prop in properties)
{
if (!string.IsNullOrEmpty(prop.Name) && prop.Value != null)
{
XElement newElement = new XElement(XName.Get(prop.Name, MSBuildNamespace));
newElement.Value = prop.Value;
if (!string.IsNullOrEmpty(prop.Condition))
{
newElement.SetAttributeValue(XName.Get("Condition", string.Empty), prop.Condition);
}
newPropertyGroup.Add(newElement);
}
}
}
}
class ProjectProperty
{
public string Name
{ get; set; }
public string Value
{ get; set; }
public string Condition
{ get; set; }
}
}
}

View File

@@ -0,0 +1,14 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System.CodeDom;
public interface IXamlBuildTypeGenerationExtension
{
bool Execute(ClassData classData, XamlBuildTypeGenerationExtensionContext buildContext);
}
}

View File

@@ -0,0 +1,13 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System.Collections.Generic;
public interface IXamlBuildTypeInspectionExtension
{
bool Execute(XamlBuildTypeInspectionExtensionContext buildContext);
}
}

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
[Serializable]
internal struct LogData
{
public string Message
{ get; set; }
public string FileName
{ get; set; }
public int LineNumber
{ get; set; }
public int LinePosition
{ get; set; }
}
}

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Runtime.Serialization;
[Serializable]
class LoggableException : Exception
{
int lineNumber;
int linePosition;
public LoggableException()
{
}
public int LineNumber
{
get
{
return this.lineNumber;
}
set
{
this.lineNumber = value;
}
}
public int LinePosition
{
get
{
return this.linePosition;
}
set
{
this.linePosition = value;
}
}
public LoggableException(string message)
: base(message)
{
}
public LoggableException(Exception innerException)
: base(innerException.Message, innerException)
{
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
if (info != null)
{
info.AddValue("lineNumber", this.lineNumber);
info.AddValue("columnNumber", this.linePosition);
}
}
}
}

View File

@@ -0,0 +1,16 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
public enum MemberVisibility
{
Public,
Private,
Family,
Assembly,
FamilyOrAssembly,
FamilyAndAssembly
}
}

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xaml;
using System.Xaml.Schema;
using XamlBuildTask;
public class NamedObject
{
MemberVisibility visibility;
public String Name
{ get; set; }
public XamlType Type
{ get; set; }
public MemberVisibility Visibility
{
get
{
return this.visibility;
}
set
{
if (!Enum.IsDefined(typeof(MemberVisibility), value))
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("value"));
}
this.visibility = value;
}
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xaml;
namespace Microsoft.Build.Tasks.Xaml
{
internal class NamespaceTable : IXamlNamespaceResolver
{
Dictionary<string, NamespaceDeclaration> tempNamespaceList = new Dictionary<string, NamespaceDeclaration>();
Stack<Dictionary<string, NamespaceDeclaration>> namespaceStack = new Stack<Dictionary<string, NamespaceDeclaration>>();
string localAssemblyName;
public NamespaceTable(string localAssemblyName)
{
this.localAssemblyName = localAssemblyName;
}
public IEnumerable<NamespaceDeclaration> GetNamespacePrefixes()
{
List<NamespaceDeclaration> list = new List<NamespaceDeclaration>();
HashSet<string> prefixSet = new HashSet<string>();
if (tempNamespaceList != null && tempNamespaceList.Count > 0)
{
foreach (NamespaceDeclaration ns in tempNamespaceList.Values)
{
if (!prefixSet.Contains(ns.Prefix))
{
prefixSet.Add(ns.Prefix);
list.Add(ns);
}
}
}
foreach (Dictionary<string, NamespaceDeclaration> currentNamespaces in this.namespaceStack)
{
foreach (NamespaceDeclaration ns in currentNamespaces.Values)
{
if (!prefixSet.Contains(ns.Prefix))
{
prefixSet.Add(ns.Prefix);
list.Add(ns);
}
}
}
return list;
}
public string GetNamespace(string prefix)
{
NamespaceDeclaration @namespace = null;
foreach (Dictionary<string, NamespaceDeclaration> currentNamespaces in this.namespaceStack)
{
if (null != currentNamespaces && currentNamespaces.TryGetValue(prefix, out @namespace))
{
return @namespace.Namespace;
}
}
if (tempNamespaceList != null && tempNamespaceList.TryGetValue(prefix, out @namespace))
{
return @namespace.Namespace;
}
return @namespace.Namespace;
}
public void ManageNamespace(XamlReader reader)
{
switch (reader.NodeType)
{
case XamlNodeType.NamespaceDeclaration:
tempNamespaceList.Add(reader.Namespace.Prefix,
new NamespaceDeclaration(
XamlBuildTaskServices.UpdateClrNamespaceUriWithLocalAssembly(reader.Namespace.Namespace, this.localAssemblyName),
reader.Namespace.Prefix));
break;
case XamlNodeType.StartObject:
case XamlNodeType.StartMember:
case XamlNodeType.GetObject:
if (tempNamespaceList != null)
{
namespaceStack.Push(tempNamespaceList);
tempNamespaceList = new Dictionary<string, NamespaceDeclaration>();
}
break;
case XamlNodeType.EndMember:
case XamlNodeType.EndObject:
namespaceStack.Pop();
break;
default:
break;
}
}
}
}

View File

@@ -0,0 +1,387 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Build.Tasks.Xaml
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using System.Threading;
using System.Xaml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.VisualStudio.Activities;
[Fx.Tag.XamlVisible(true)]
public class PartialClassGenerationTask : Task
{
const string DefaultGeneratedSourceExtension = "g";
List<ITaskItem> generatedResources = new List<ITaskItem>();
List<ITaskItem> generatedCodeFiles = new List<ITaskItem>();
// We will do Dev10 behavior if the new required property MSBuildProjectDirectory is NOT specified. This can happen
// if a Dev10 version of the Microsoft.Xaml.Targets file is being used with Dev11 installed.
bool supportExtensions = false;
string msBuildProjectDirectory;
public PartialClassGenerationTask()
{
this.GeneratedSourceExtension = DefaultGeneratedSourceExtension;
}
[Fx.Tag.KnownXamlExternal]
[Output]
public ITaskItem[] ApplicationMarkup { get; set; }
public string AssemblyName
{ get; set; }
public string[] KnownReferencePaths { get; set; }
[Fx.Tag.KnownXamlExternal]
[Output]
public ITaskItem[] GeneratedResources
{
get
{
return generatedResources.ToArray();
}
set
{
generatedResources = new List<ITaskItem>(value);
}
}
[Fx.Tag.KnownXamlExternal]
[Output]
public ITaskItem[] GeneratedCodeFiles
{
get
{
return generatedCodeFiles.ToArray();
}
set
{
generatedCodeFiles = new List<ITaskItem>(value);
}
}
public string GeneratedSourceExtension
{ get; set; }
[Required]
public string Language
{ get; set; }
[Required]
public string OutputPath
{ get; set; }
// This is Required for Dev11, but to allow things to work with a Dev10 targets file, we are not marking it required.
public string MSBuildProjectDirectory
{
get
{
return this.msBuildProjectDirectory;
}
set
{
this.msBuildProjectDirectory = value;
// The fact that this property is being set indicates that a Dev11 version of the targets
// file is being used, so we should not do Dev10 behavior.
this.supportExtensions = true;
}
}
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] References
{ get; set; }
public string RootNamespace
{ get; set; }
[Fx.Tag.KnownXamlExternal]
public ITaskItem[] SourceCodeFiles
{ get; set; }
[Output]
public bool RequiresCompilationPass2
{ get; set; }
public string BuildTaskPath
{ get; set; }
public bool IsInProcessXamlMarkupCompile
{ get; set; }
public ITaskItem[] XamlBuildTypeGenerationExtensionNames
{ get; set; }
public ITaskItem[] XamlBuildTypeInspectionExtensionNames
{ get; set; }
private static AppDomain inProcessAppDomain;
private static Dictionary<string, DateTime> referencesTimeStampCache;
private Object referencesCacheLock = new Object();
public override bool Execute()
{
VSDesignerPerfEventProvider perfEventProvider = new VSDesignerPerfEventProvider();
perfEventProvider.WriteEvent(VSDesignerPerfEvents.XamlBuildTaskExecuteStart);
try
{
if (IsInProcessXamlMarkupCompile)
{
bool acquiredLock = false;
try
{
Monitor.TryEnter(referencesCacheLock, ref acquiredLock);
if (acquiredLock)
{
return ReuseAppDomainAndExecute();
}
else
{
return GetAppDomainAndExecute();
}
}
finally
{
if (acquiredLock)
{
Monitor.Exit(referencesCacheLock);
}
}
}
else
{
return GetAppDomainAndExecute();
}
}
finally
{
perfEventProvider.WriteEvent(VSDesignerPerfEvents.XamlBuildTaskExecuteEnd);
}
}
bool ReuseAppDomainAndExecute()
{
AppDomain appDomain = null;
bool createdNewAppDomain = false;
try
{
try
{
appDomain = GetInProcessAppDomain(out createdNewAppDomain);
bool ret = ExecuteInternal(appDomain);
return ret;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (createdNewAppDomain)
{
XamlBuildTaskServices.LogException(this.Log, e.Message);
return false;
}
else
{
AppDomain.Unload(inProcessAppDomain);
inProcessAppDomain = null;
return GetAppDomainAndExecute();
}
}
}
finally
{
if (Log != null)
{
Log.MarkAsInactive();
}
}
}
bool GetAppDomainAndExecute()
{
AppDomain appDomain = null;
try
{
appDomain = CreateNewAppDomain();
bool ret = ExecuteInternal(appDomain);
return ret;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
XamlBuildTaskServices.LogException(this.Log, e.Message);
return false;
}
finally
{
if (appDomain != null)
{
AppDomain.Unload(appDomain);
}
}
}
bool ExecuteInternal(AppDomain appDomain)
{
PartialClassGenerationTaskInternal wrapper = (PartialClassGenerationTaskInternal)appDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof(PartialClassGenerationTaskInternal).FullName);
PopulateBuildArtifacts(wrapper);
bool ret = wrapper.Execute();
if (ret)
{
ExtractBuiltArtifacts(wrapper);
}
return ret;
}
AppDomain CreateNewAppDomain()
{
return XamlBuildTaskServices.CreateAppDomain("PartialClassAppDomain_" + Guid.NewGuid(), BuildTaskPath);
}
// For Intellisense builds, we re-use the AppDomain for successive builds instead of creating a new one every time,
// if the references have not changed (there are no new references and they have not been updated since the last build)
// This method accesses the static referencesTimeStampCache (indirectly).
// To ensure thread safety, this method should be called inside a lock/monitor
AppDomain GetInProcessAppDomain(out bool newAppDomain)
{
newAppDomain = false;
if (inProcessAppDomain == null)
{
inProcessAppDomain = CreateNewAppDomain();
newAppDomain = true;
UpdateReferenceCache();
}
else if (AreReferencesChanged())
{
AppDomain.Unload(inProcessAppDomain);
inProcessAppDomain = CreateNewAppDomain();
newAppDomain = true;
UpdateReferenceCache();
}
return inProcessAppDomain;
}
// This method accesses the static referencesTimeStampCache.
// To ensure thread safety, this method should be called inside a lock/monitor
bool AreReferencesChanged()
{
bool refsChanged = false;
if (referencesTimeStampCache == null || referencesTimeStampCache.Count != References.Length)
{
refsChanged = true;
}
else
{
foreach (var reference in References)
{
string fullPath = Path.GetFullPath(reference.ItemSpec);
DateTime timeStamp = File.GetLastWriteTimeUtc(fullPath);
if (!referencesTimeStampCache.ContainsKey(fullPath)
|| timeStamp > referencesTimeStampCache[fullPath]
|| timeStamp == DateTime.MinValue)
{
refsChanged = true;
break;
}
}
}
return refsChanged;
}
// This method accesses the static referencesTimeStampCache.
// To ensure thread safety, this method should be called inside a lock/monitor
void UpdateReferenceCache()
{
referencesTimeStampCache = new Dictionary<string, DateTime>();
foreach (var reference in References)
{
string fullPath = Path.GetFullPath(reference.ItemSpec);
DateTime timeStamp = File.GetLastWriteTimeUtc(fullPath);
referencesTimeStampCache.Add(fullPath, timeStamp);
}
}
void PopulateBuildArtifacts(PartialClassGenerationTaskInternal wrapper)
{
IList<ITaskItem> applicationMarkup = null;
if (this.ApplicationMarkup != null)
{
applicationMarkup = this.ApplicationMarkup
.Select(i => new DelegatingTaskItem(i) as ITaskItem).ToList();
}
wrapper.ApplicationMarkup = applicationMarkup;
wrapper.BuildLogger = this.Log;
wrapper.References = this.References
.Select(i => new DelegatingTaskItem(i) as ITaskItem).ToList();
IList<string> sourceCodeFiles = null;
if (this.SourceCodeFiles != null)
{
sourceCodeFiles = new List<string>(this.SourceCodeFiles.Length);
foreach (ITaskItem taskItem in this.SourceCodeFiles)
{
sourceCodeFiles.Add(taskItem.ItemSpec);
}
}
wrapper.SourceCodeFiles = sourceCodeFiles;
wrapper.Language = this.Language;
wrapper.AssemblyName = this.AssemblyName;
wrapper.OutputPath = this.OutputPath;
wrapper.RootNamespace = this.RootNamespace;
wrapper.GeneratedSourceExtension = this.GeneratedSourceExtension;
wrapper.IsInProcessXamlMarkupCompile = this.IsInProcessXamlMarkupCompile;
wrapper.MSBuildProjectDirectory = this.MSBuildProjectDirectory;
wrapper.XamlBuildTaskTypeGenerationExtensionNames = XamlBuildTaskServices.GetXamlBuildTaskExtensionNames(this.XamlBuildTypeGenerationExtensionNames);
if (this.XamlBuildTypeInspectionExtensionNames != null && this.XamlBuildTypeInspectionExtensionNames.Length > 0)
{
wrapper.MarkupCompilePass2ExtensionsPresent = true;
}
wrapper.SupportExtensions = this.supportExtensions;
}
void ExtractBuiltArtifacts(PartialClassGenerationTaskInternal wrapper)
{
foreach (string resource in wrapper.GeneratedResources)
{
this.generatedResources.Add(new TaskItem(resource));
}
foreach (string code in wrapper.GeneratedCodeFiles)
{
this.generatedCodeFiles.Add(new TaskItem(code));
}
this.RequiresCompilationPass2 = wrapper.RequiresCompilationPass2 ||
(this.XamlBuildTypeInspectionExtensionNames != null && this.XamlBuildTypeInspectionExtensionNames.Length > 0);
}
}
}

Some files were not shown because too many files have changed in this diff Show More