[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / XamlBuildTask / Microsoft / Build / Tasks / Xaml / XamlBuildTaskServices.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace Microsoft.Build.Tasks.Xaml
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.IO;
10     using System.Security;
11     using System.Xaml;
12     using System.Xaml.Schema;
13     using System.Xml;
14     using System.Xml.Linq;
15     using Microsoft.Build.Utilities;
16     using System.Reflection;
17     using System.Globalization;
18     using System.Diagnostics.CodeAnalysis;
19     using System.Runtime;
20     using System.CodeDom;
21     using System.ComponentModel;
22     using System.CodeDom.Compiler;
23     using System.Linq;
24     using Microsoft.Build.Framework;
25     using XamlBuildTask;
26
27     internal static class XamlBuildTaskServices
28     {
29
30         internal const string ClrNamespaceUriNamespacePart = "clr-namespace:";
31         internal const string ClrNamespaceUriAssemblyPart = "assembly=";
32         internal const string XamlExtension = ".xaml";
33
34
35         //internal static XName SchemaTypeName = XamlSchemaTypeResolver.Default.GetTypeReference(typeof(SchemaType)).Name;
36         const string UnknownExceptionErrorCode = "XC1000";
37         // Update this value if any changes are made to it in System.Xaml\KnownStrings.cs
38         const string serializerReferenceNamePrefix = "__ReferenceID";
39
40         internal static string SerializerReferenceNamePrefix
41         { get { return serializerReferenceNamePrefix; } }
42
43         static string _private = String.Empty;
44         internal static string PrivateModifier
45         { get { return _private; } }
46
47         static string _public = String.Empty;
48         internal static string PublicModifier
49         { get { return _public; } }
50
51         static string _internal = String.Empty;
52         internal static string InternalModifier
53         { get { return _internal; } }
54
55         static string _protected = String.Empty;
56         internal static string ProtectedModifier
57         { get { return _protected; } }
58
59         static string _protectedInternal = String.Empty;
60         internal static string ProtectedInternalModifier
61         { get { return _protectedInternal; } }
62
63         static string _protectedAndInternal = String.Empty;
64         internal static string ProtectedAndInternalModifier
65         { get { return _protectedAndInternal; } }
66
67         static string _publicClass = String.Empty;
68         internal static string PublicClassModifier
69         { get { return _publicClass; } }
70
71         static string _internalClass = String.Empty;
72         internal static string InternalClassModifier
73         { get { return _internalClass; } }
74
75         static string _fileNotLoaded = String.Empty;
76         internal static string FileNotLoaded
77         {
78             get { return _fileNotLoaded; }
79         }
80
81         internal static void PopulateModifiers(CodeDomProvider codeDomProvider)
82         {
83             TypeConverter memberAttributesConverter = codeDomProvider.GetConverter(typeof(MemberAttributes));
84             if (memberAttributesConverter != null)
85             {
86                 if (memberAttributesConverter.CanConvertTo(typeof(string)))
87                 {
88                     try
89                     {
90                         _private = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.Private).ToUpperInvariant();
91                         _public = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.Public).ToUpperInvariant();
92                         _protected = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.Family).ToUpperInvariant();
93                         _internal = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.Assembly).ToUpperInvariant();
94                         _protectedInternal = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.FamilyOrAssembly).ToUpperInvariant();
95                         _protectedAndInternal = memberAttributesConverter.ConvertToInvariantString(MemberAttributes.FamilyAndAssembly).ToUpperInvariant();
96                     }
97                     catch (NotSupportedException)
98                     {
99                     }
100                 }
101             }
102
103             TypeConverter typeAttributesConverter = codeDomProvider.GetConverter(typeof(TypeAttributes));
104             if (typeAttributesConverter != null)
105             {
106                 if (typeAttributesConverter.CanConvertTo(typeof(string)))
107                 {
108                     try
109                     {
110                         _internalClass = typeAttributesConverter.ConvertToInvariantString(TypeAttributes.NotPublic).ToUpperInvariant();
111                         _publicClass = typeAttributesConverter.ConvertToInvariantString(TypeAttributes.Public).ToUpperInvariant();
112                     }
113                     catch (NotSupportedException)
114                     {
115                     }
116                 }
117             }
118         }
119
120         internal static bool IsPublic(string classModifier)
121         {
122             if (!string.IsNullOrEmpty(classModifier))
123             {
124                 if (string.Equals(classModifier, InternalClassModifier, StringComparison.OrdinalIgnoreCase))
125                 {
126                     return false;
127                 }
128                 else if (string.Equals(classModifier, PublicClassModifier, StringComparison.OrdinalIgnoreCase))
129                 {
130                     return true;
131                 }
132                 else
133                 {
134                     throw FxTrace.Exception.AsError(
135                         new InvalidOperationException(SR.ClassModifierNotSupported(classModifier)));
136                 }
137             }
138             return true;
139         }
140
141         internal static MemberVisibility GetMemberVisibility(string memberModifier)
142         {
143             if (!string.IsNullOrEmpty(memberModifier))
144             {
145                 if (string.Equals(memberModifier, XamlBuildTaskServices.PrivateModifier, StringComparison.OrdinalIgnoreCase))
146                 {
147                     return MemberVisibility.Private;
148                 }
149                 else if (string.Equals(memberModifier, XamlBuildTaskServices.PublicModifier, StringComparison.OrdinalIgnoreCase))
150                 {
151                     return MemberVisibility.Public;
152                 }
153                 else if (string.Equals(memberModifier, XamlBuildTaskServices.ProtectedModifier, StringComparison.OrdinalIgnoreCase))
154                 {
155                     return MemberVisibility.Family;
156                 }
157                 else if (string.Equals(memberModifier, XamlBuildTaskServices.InternalModifier, StringComparison.OrdinalIgnoreCase))
158                 {
159                     return MemberVisibility.Assembly;
160                 }
161                 else if (string.Equals(memberModifier, XamlBuildTaskServices.ProtectedInternalModifier, StringComparison.OrdinalIgnoreCase))
162                 {
163                     return MemberVisibility.FamilyOrAssembly;
164                 }
165                 else if (string.Equals(memberModifier, XamlBuildTaskServices.ProtectedAndInternalModifier, StringComparison.OrdinalIgnoreCase))
166                 {
167                     return MemberVisibility.FamilyAndAssembly;
168                 }
169                 else
170                 {
171                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.FieldModifierNotSupported(memberModifier)));
172                 }
173             }
174             // Public is only the default modifier for properties, not for fields.
175             // But we explicitly set the default modifier for fields (in ClassImporter), so if the
176             // modifier is null or empty, it must be a property, and so we return public.
177             // This is consistent with Dev10.
178             return MemberVisibility.Public;
179         }
180
181         public static Assembly ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
182         {
183             string[] parts = args.Name.Split(',');
184             foreach (var asm in AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies())
185             {
186                 AssemblyName assemblyName = asm.GetName();
187
188                 if (assemblyName.Name.Equals(parts[0], StringComparison.OrdinalIgnoreCase))
189                 {
190                     return asm;
191                 }
192             }
193
194             // The fact that the file can not be found in the referenced assembly list means that 
195             // CLR will throw a FileLoadException once this event handler returns.
196             // Since the FileLoadException's FileName property is set to null (due to the fact there is no path),
197             // we are storing it in a static variable so that we can print a pretty error message later on.
198
199             _fileNotLoaded = args.Name;
200
201             return null;
202         }
203
204         public static AppDomain CreateAppDomain(string friendlyName, string buildTaskPath)
205         {
206             if (buildTaskPath == null)
207             {
208                 throw FxTrace.Exception.AsError(new LoggableException(new InvalidOperationException(SR.BuildTaskPathMustNotBeNull)));
209             }
210
211             // Enable shadow copying in the Designer appdomain, so that we can continue to rebuild
212             // projects in the solution even if designer has loaded the assemblies that were referenced in current project
213             AppDomainSetup appDomainSetup = new AppDomainSetup();
214             appDomainSetup.ShadowCopyFiles = "true";
215             appDomainSetup.ApplicationBase = buildTaskPath;
216             appDomainSetup.LoaderOptimization = LoaderOptimization.MultiDomainHost;
217
218             // Create appdomain with fulltrust.
219             return AppDomain.CreateDomain(
220                 friendlyName,
221                 AppDomain.CurrentDomain.Evidence,
222                 appDomainSetup,
223                 new NamedPermissionSet("FullTrust"));
224         }
225
226         internal static IList<Assembly> Load(IList<ITaskItem> referenceAssemblies, bool isDesignTime)
227         {
228             List<string> systemReferences = new List<string>();
229             List<string> nonSystemReferences = new List<string>();
230
231             CategorizeReferenceAssemblies(referenceAssemblies, out systemReferences, out nonSystemReferences);
232
233             IList<Assembly> assemblies = new List<Assembly>();
234             foreach (string item in systemReferences)
235             {
236                 assemblies.Add(Load(item));
237             }
238
239             foreach (string item in nonSystemReferences)
240             {
241                 try
242                 {
243                     assemblies.Add(Load(item));
244                 }
245                 catch (FileNotFoundException)
246                 {
247                     // file not found on P2P references is allowed.
248                     // The design time build can run before the DLL's are present
249                     if (!isDesignTime)
250                     {
251                         throw;
252                     }
253                 }
254             }
255
256             bool mscorlibFound = false;
257
258             foreach (Assembly asm in assemblies)
259             {
260                 // here we want to check if the assembly is mscorlib.dll.
261                 // for the current codebase, this check would have worked:
262                 // if (asm == typeof(Object).Assembly), but we 
263                 // prefer a check that will continue to work when LMR is used
264                 if (asm.GetReferencedAssemblies().Length == 0)
265                 {
266                     mscorlibFound = true;
267                 }
268             }
269
270             if (!mscorlibFound)
271             {
272                 assemblies.Add(typeof(Object).Assembly);
273             }
274
275             return assemblies;
276         }
277
278         [SuppressMessage(FxCop.Category.Reliability, FxCop.Rule.AvoidCallingProblematicMethods,
279             Justification = "Using LoadFile to avoid loading through Fusion and load the exact assembly the developer specified")]
280         internal static Assembly Load(string reference)
281         {
282             if (reference.EndsWith("mscorlib.dll", StringComparison.OrdinalIgnoreCase))
283             {
284                 return typeof(Object).Assembly;
285             }
286             string fullPath = Path.GetFullPath(reference);
287             try
288             {
289                 return Assembly.ReflectionOnlyLoadFrom(fullPath);
290             }
291             catch (FileNotFoundException e)
292             {
293                 if (e.FileName == null)
294                 {
295                     throw FxTrace.Exception.AsError((new FileNotFoundException(e.Message, fullPath)));
296                 }
297                 else
298                     throw;
299             }
300         }
301
302         internal static void LogException(TaskLoggingHelper buildLogger, string message)
303         {
304             LogException(buildLogger, message, null, 0, 0);
305         }
306
307         internal static void LogException(TaskLoggingHelper buildLogger, string message, string fileName, int lineNumber, int linePosition)
308         {
309             string errorCode, logMessage;
310             ExtractErrorCodeAndMessage(buildLogger, message, out errorCode, out logMessage);
311             buildLogger.LogError(null, errorCode, null, fileName, lineNumber, linePosition, 0, 0, logMessage, null);
312         }
313
314         static void ExtractErrorCodeAndMessage(TaskLoggingHelper buildLogger, string message, out string errorCode, out string logMessage)
315         {
316             errorCode = buildLogger.ExtractMessageCode(message, out logMessage);
317             if (string.IsNullOrEmpty(errorCode))
318             {
319                 errorCode = UnknownExceptionErrorCode;
320                 logMessage = SR.UnknownBuildError(message);
321             }
322         }
323
324         internal static bool IsClrNamespaceUri(string nsName, out int nsIndex, out int assemblyIndex)
325         {
326             if (nsName.StartsWith(ClrNamespaceUriNamespacePart, StringComparison.Ordinal))
327             {
328                 int semicolonIndex = nsName.IndexOf(';');
329                 if (semicolonIndex == -1 || nsName.Trim().EndsWith(";", StringComparison.Ordinal))
330                 {
331                     nsIndex = ClrNamespaceUriNamespacePart.Length;
332                     assemblyIndex = -1;
333                     return true;
334                 }
335                 else
336                 {
337                     int equalsIndex = nsName.IndexOf('=', semicolonIndex);
338                     if (equalsIndex != -1)
339                     {
340                         int start = ClrNamespaceUriNamespacePart.Length;
341                         int assemblyStart = semicolonIndex + 1;
342                         if (equalsIndex - semicolonIndex == ClrNamespaceUriAssemblyPart.Length)
343                         {
344                             for (int i = 0; i < ClrNamespaceUriAssemblyPart.Length; i++)
345                             {
346                                 if (nsName[assemblyStart + i] != ClrNamespaceUriAssemblyPart[i])
347                                 {
348                                     nsIndex = -1;
349                                     assemblyIndex = -1;
350                                     return false;
351                                 }
352                             }
353
354                             nsIndex = start;
355                             assemblyIndex = assemblyStart + ClrNamespaceUriAssemblyPart.Length;
356                             return true;
357                         }
358                     }
359                 }
360             }
361             nsIndex = -1;
362             assemblyIndex = -1;
363             return false;
364         }
365
366         internal static string UpdateClrNamespaceUriWithLocalAssembly(string @namespace, string localAssemblyName)
367         {
368             return UpdateClrNamespaceUriWithLocalAssembly(@namespace, localAssemblyName, null);
369         }
370
371         internal static string UpdateClrNamespaceUriWithLocalAssembly(string @namespace, string localAssemblyName, string realAssemblyName)
372         {
373             int nsIndex, assemblyIndex;
374             if (IsClrNamespaceUri(@namespace, out nsIndex, out assemblyIndex))
375             {
376                 // If assembly portion of namespace does not exist, assume that this is part of the local assembly
377                 if (assemblyIndex == -1)
378                 {
379                     return string.Format(CultureInfo.InvariantCulture, "{0};{1}{2}",
380                         @namespace.TrimEnd(' ', ';'), XamlBuildTaskServices.ClrNamespaceUriAssemblyPart, localAssemblyName);
381                 }
382                 else if (!string.IsNullOrEmpty(realAssemblyName) &&
383                     localAssemblyName != realAssemblyName &&
384                     @namespace.Substring(assemblyIndex) == realAssemblyName)
385                 {
386                     return string.Format(CultureInfo.InvariantCulture, "{0}{1}",
387                         @namespace.Substring(0, assemblyIndex), localAssemblyName);
388                 }
389             }
390             return @namespace;
391         }
392
393         internal static string GetFullTypeName(XamlType xamlType)
394         {
395             string typeName = GetFullTypeNameWithoutNamespace(xamlType);
396             typeName = xamlType.PreferredXamlNamespace + ":" + typeName;
397             return typeName;
398         }
399
400         private static string GetFullTypeNameWithoutNamespace(XamlType xamlType)
401         {
402             string typeName = string.Empty;
403             if (xamlType != null)
404             {
405                 typeName = xamlType.Name;
406                 bool firstTypeArg = true;
407                 if (xamlType.TypeArguments != null && xamlType.TypeArguments.Count > 0)
408                 {
409                     typeName += "(";
410                     foreach (XamlType typeArg in xamlType.TypeArguments)
411                     {
412                         if (!firstTypeArg)
413                         {
414                             typeName += ",";
415                         }
416                         else
417                         {
418                             firstTypeArg = false;
419                         }
420                         typeName += typeArg.Name;
421                     }
422                     typeName += ")";
423                 }
424             }
425             return typeName;
426         }
427
428         internal static XamlType GetXamlTypeFromString(string typeName, NamespaceTable namespaceTable, XamlSchemaContext xsc)
429         {
430             XamlTypeName xamlTypeName = XamlTypeName.Parse(typeName, namespaceTable);
431             XamlType xamlType = xsc.GetXamlType(xamlTypeName);
432             if (xamlType == null)
433             {
434                 xamlType = GetXamlTypeFromXamlTypeName(xamlTypeName, namespaceTable, xsc);
435             }
436             return xamlType;
437         }
438
439         static XamlType GetXamlTypeFromXamlTypeName(XamlTypeName xamlTypeName, NamespaceTable namespaceTable, XamlSchemaContext xsc)
440         {
441             IList<XamlType> typeArgs = null;
442             if (xamlTypeName.TypeArguments.Count > 0)
443             {
444                 typeArgs = new List<XamlType>();
445                 foreach (var typeArg in xamlTypeName.TypeArguments)
446                 {
447                     typeArgs.Add(GetXamlTypeFromXamlTypeName(typeArg, namespaceTable, xsc));
448                 }
449             }
450             return new XamlType(xamlTypeName.Namespace, xamlTypeName.Name, typeArgs, xsc);
451         }      
452
453         internal static bool TryGetClrTypeName(XamlType xamlType, string rootNamespace, out string clrTypeName)
454         {
455             bool isLocal;   
456             return TryGetClrTypeName(xamlType, rootNamespace, out clrTypeName, out isLocal);
457         }
458
459         internal static bool TryGetClrTypeName(XamlType xamlType, string rootNamespace, out string clrTypeName, out bool isLocal)
460         {
461             if (!xamlType.IsUnknown)
462             {
463                 isLocal = false;
464                 clrTypeName = xamlType.UnderlyingType != null ? xamlType.UnderlyingType.FullName : null;
465                 return (clrTypeName != null);
466             }
467             else
468             {
469                 isLocal = true;
470                 return TryGetClrTypeNameFromLocalType(xamlType, rootNamespace, out clrTypeName);
471             }
472         }
473
474         internal static bool TryExtractClrNs(string @namespace, out string clrNs)
475         {
476             int nsIndex, assemblyIndex;
477             if (XamlBuildTaskServices.IsClrNamespaceUri(@namespace, out nsIndex, out assemblyIndex))
478             {
479                 clrNs = (assemblyIndex == -1)
480                     ? @namespace.Substring(nsIndex).TrimEnd(' ', ';')
481                     : @namespace.Substring(
482                         nsIndex,
483                         assemblyIndex - XamlBuildTaskServices.ClrNamespaceUriAssemblyPart.Length - nsIndex - 1).TrimEnd(' ', ';');
484                 return true;
485             }
486             else
487             {
488                 clrNs = null;
489                 return false;
490             }
491         }
492
493         static bool TryGetClrTypeNameFromLocalType(XamlType xamlType, string rootNamespace, out string clrTypeName)
494         {
495             //
496             // This means that either we have a type in the base hierarchy or type arguments
497             // that is invalid or it's in the local (current) project.
498             string @namespace = xamlType.PreferredXamlNamespace;
499             string name = xamlType.Name;
500             string clrNs;
501
502             if (@namespace != null && TryExtractClrNs(@namespace, out clrNs))
503             {
504                 if (!String.IsNullOrEmpty(rootNamespace) && 
505                     !String.IsNullOrEmpty(clrNs) &&
506                     clrNs.StartsWith(rootNamespace, StringComparison.OrdinalIgnoreCase))
507                 {
508                     if (clrNs.Length > rootNamespace.Length)
509                     {
510                         clrNs = clrNs.Substring(rootNamespace.Length + 1);
511                     }
512                     else
513                     {
514                         clrNs = string.Empty;
515                     }
516                 } 
517                 if (string.IsNullOrEmpty(clrNs))
518                 {
519                     clrTypeName = name;
520                 }
521                 else
522                 {
523                     clrTypeName = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", clrNs, name);
524                 }
525                 return true;
526             }
527             else
528             {
529                 // This could be an open generic with local type-args. Or it could be a known type arg
530                 // that we didn't resolve earlier because it was an arg to a local open generic.
531                 // Either way we should try to re-resolve it here.
532                 string qualifiedName = name;
533                 if (xamlType.TypeArguments != null && xamlType.TypeArguments.Count > 0)
534                 {
535                     qualifiedName = name + "`" + xamlType.TypeArguments.Count;
536                 }
537                 XamlType resolvedType = xamlType.SchemaContext.GetXamlType(new XamlTypeName(@namespace, qualifiedName));
538                 if (resolvedType != null && resolvedType.UnderlyingType != null)
539                 {
540                     clrTypeName = resolvedType.UnderlyingType.FullName;
541                     return true;
542                 }
543             }
544             clrTypeName = null;
545             return false;
546         }
547
548         // Returns true if type namespace is clr-namespace and populates assemblyName
549         // Else returns false with assemblyName null;
550         internal static bool GetTypeNameInAssemblyOrNamespace(XamlType type, string localAssemblyName, string realAssemblyName, 
551             out string typeName, out string assemblyName, out string ns)
552         {
553             int assemblyIndex, nsIndex;
554             string typeNs = type.PreferredXamlNamespace;
555             typeName = GetFullTypeNameWithoutNamespace(type);
556             if (IsClrNamespaceUri(typeNs, out nsIndex, out assemblyIndex))
557             {
558                 assemblyName = assemblyIndex > -1 ? typeNs.Substring(assemblyIndex) : String.Empty;
559                 if ((!string.IsNullOrEmpty(localAssemblyName) && assemblyName.Contains(localAssemblyName)) || string.IsNullOrEmpty(assemblyName))
560                 {
561                     assemblyName = realAssemblyName;
562                 }
563                 int nsLength = typeNs.IndexOf(';') - nsIndex;
564                 if (nsLength > 0)
565                 {
566                     ns = typeNs.Substring(nsIndex, nsLength);
567                 }
568                 else
569                 {
570                     ns = typeNs.Substring(nsIndex);
571                 }
572                 return true;
573             }
574             else
575             {
576                 assemblyName = null;
577                 ns = typeNs;
578                 return false;
579             }
580         }
581
582         internal static string GetTypeName(XamlType type, string localAssemblyName, string realAssemblyName)
583         {
584             string typeName, assemblyName, ns;
585             if (GetTypeNameInAssemblyOrNamespace(type, localAssemblyName, realAssemblyName, out typeName, out assemblyName, out ns))
586             {
587                 return ns + "." + typeName;
588             }
589             else
590             {
591                 return ns + ":" + typeName;
592             }
593         }
594
595         // Returns false if the type is known else returns true.
596         internal static bool GetUnresolvedLeafTypeArg(XamlType type, ref IList<XamlType> unresolvedLeafTypeList)
597         {
598             if (unresolvedLeafTypeList != null && type != null && type.IsUnknown)
599             {
600                 if (!type.IsGeneric)
601                 {
602                     unresolvedLeafTypeList.Add(type);
603                 }
604                 else
605                 {
606                     bool hasUnknownChildren = false;
607                     foreach (XamlType typeArg in type.TypeArguments)
608                     {
609                         hasUnknownChildren |= GetUnresolvedLeafTypeArg(typeArg, ref unresolvedLeafTypeList);
610                     }
611                     if (!hasUnknownChildren)
612                     {
613                         unresolvedLeafTypeList.Add(type);
614                     }
615                 }
616                 return true;
617             }
618             else
619             {
620                 return false;
621             }
622         }
623
624         [SuppressMessage(FxCop.Category.Reliability, FxCop.Rule.AvoidCallingProblematicMethods,
625             Justification = "Using LoadFrom to avoid loading through Fusion and load from the exact path specified")]
626         internal static IEnumerable<T> GetXamlBuildTaskExtensions<T>(IList<Tuple<string, string, string>> extensionNames, TaskLoggingHelper logger, string currentProjectDirectory) where T : class
627         {            
628             List<T> extensionsLoaded = new List<T>();
629
630             if (extensionNames == null)
631             {
632                 return extensionsLoaded;
633             }
634
635             foreach (Tuple<string, string, string> extensionEntry in extensionNames)
636             {
637                 Assembly assembly = null;
638                 string assemblyName = extensionEntry.Item2;
639                 string assemblyFile = extensionEntry.Item3;
640                 if (!string.IsNullOrEmpty(assemblyName))
641                 {
642                     try
643                     {
644                         // try to load using the assembly name
645                         assembly = Assembly.Load(assemblyName);
646                     }
647                     catch (Exception e)
648                     {
649                         if (Fx.IsFatal(e))
650                         {
651                             throw;                            
652                         }
653                         logger.LogWarning(SR.UnresolvedExtensionAssembly(assemblyName));
654                     }
655                 }
656                 else
657                 {
658                     try 
659                     {
660                         if (Path.IsPathRooted(assemblyFile))
661                         {
662                             // if the path is absolute, we just load from the given location
663                             assembly = Assembly.LoadFrom(assemblyFile);
664                         }
665                         else
666                         {
667                             // if the path is relative, we load from 
668                             // current project folder + provided relative path
669                             assembly = Assembly.LoadFrom(Path.Combine(currentProjectDirectory, assemblyFile));
670                         }
671                     }
672                     catch (Exception e)
673                     {
674                         if (Fx.IsFatal(e))
675                         {
676                             throw;
677                         }
678                         logger.LogWarning(SR.UnresolvedExtensionAssembly(assemblyFile));
679                     }
680                 }               
681
682                 if (assembly == null)
683                 {
684                     continue;
685                 }
686
687                 Type extensionType = assembly.GetType(extensionEntry.Item1);
688
689                 if (extensionType == null || extensionType.GetInterface(typeof(T).FullName) == null)
690                 {
691                     string assemblylocationInfo = assemblyFile != "" ? assemblyFile : assemblyName;
692                     logger.LogWarning(SR.UnresolvedExtension(extensionEntry.Item1, assemblylocationInfo));
693                     continue;
694                 }
695                 
696                 T extension;
697                 try
698                 {
699                     extension = Activator.CreateInstance(extensionType) as T;
700                 }
701                 catch (Exception e)
702                 {
703                     if (Fx.IsFatal(e))
704                     {
705                         throw;
706                     }
707
708                     logger.LogWarning(SR.ExceptionThrownDuringConstruction(extensionEntry.Item1,
709                         e.GetType().ToString(),
710                         e.Message,
711                         e.InnerException != null ? e.InnerException.GetType().ToString() : "null",
712                         e.InnerException != null ? e.InnerException.Message : "null"));
713
714                     continue;
715                 }
716
717                 if (extension != null)
718                 {
719                     extensionsLoaded.Add(extension);                    
720                 }                
721             }
722             return extensionsLoaded;
723         }
724
725         internal static IList<Tuple<string, string, string>> GetXamlBuildTaskExtensionNames(ITaskItem[] xamlBuildTypeGenerationExtensionsNames)
726         {
727             List<Tuple<string, string, string>> extensionNames = new List<Tuple<string, string, string>>();
728             if (xamlBuildTypeGenerationExtensionsNames != null)
729             {
730                 string assemblyFile;
731                 string assemblyName;
732                 foreach (ITaskItem taskItem in xamlBuildTypeGenerationExtensionsNames)
733                 {
734                     assemblyFile = taskItem.GetMetadata("AssemblyFile");
735                     assemblyName = taskItem.GetMetadata("AssemblyName");
736                     if (assemblyName != "" && assemblyFile != "")
737                     {
738                         throw FxTrace.Exception.AsError(new LoggableException(SR.BothAssemblyNameAndFileSpecified));
739                     }
740                     if (assemblyName == "" && assemblyFile == "")
741                     {
742                         throw FxTrace.Exception.AsError(new LoggableException(SR.AssemblyNameOrFileNotSpecified));
743                     }
744                     
745                     extensionNames.Add(new Tuple<string, string, string>(taskItem.ItemSpec, assemblyName, assemblyFile));
746                 }
747             }
748             return extensionNames;
749         }
750
751         internal static IList<string> GetReferences(IList<ITaskItem> referenceAssemblies)
752         {
753             IList<string> references = new List<string>();
754             foreach (var reference in referenceAssemblies)
755             {
756                 references.Add(reference.ItemSpec);
757             }
758
759             return references;
760         }
761
762         private static void CategorizeReferenceAssemblies(IList<ITaskItem> referenceAssemblies, out List<string> systemItems, out List<string> nonSystemItems)
763         {
764             List<string> systemList = new List<string>();
765             List<string> nonSystemList = new List<string>();
766             foreach (ITaskItem item in referenceAssemblies)
767             {
768                 string resolvedFrom = item.GetMetadata("ResolvedFrom");
769                 string isSystemReference = item.GetMetadata("IsSystemReference");
770                 string asmName = Path.GetFileName(item.ItemSpec);
771
772                 bool isMsCorLib = asmName.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase);
773                 bool isManagedSystemMetadata = !String.IsNullOrEmpty(isSystemReference)
774                     && isSystemReference.Equals("True", StringComparison.OrdinalIgnoreCase);
775                 bool isNativeSystemMetadata = resolvedFrom != null
776                     && (resolvedFrom == "GetSDKReferenceFiles" || resolvedFrom == "{TargetFrameworkDirectory}");
777
778                 if (isManagedSystemMetadata || isNativeSystemMetadata || isMsCorLib)
779                 {
780                     systemList.Add(item.ItemSpec);
781                 }
782                 else
783                 {
784                     nonSystemList.Add(item.ItemSpec);
785                 }
786             }
787
788             systemItems = systemList;
789             nonSystemItems = nonSystemList;
790         }
791     }
792
793
794 }